#include "compiler.h"
#include "lexer.h"
#include <stdio.h>
#include "../散列表_unicode切片_编码/散列表_unicode切片_编码.h"

/******************************************************************************
 *                                   语法分析
 * 词法分析 >> 单词信息体 》》  语法分析器  》》 语法分析树 -> 抽象语法树
 * 原理：LL(1)右读向下分析文法 + 表达式算符优先文法
 *****************************************************************************/
// 维护函数
单词信息体 读入下一单词();

// 声明节点
签名节点 * 解析器_创建签名节点(uint8_t 节点类型);
// 语句节点
三元节点 * 解析器_创建三元节点(uint8_t 节点类型, 三元节点* 左指针, 三元节点* 中指针, 三元节点* 右指针);
// 表达式节点
列表节点 * 解析器_创建列表节点(节点类型 类型);
    void 列表节点_扩容(列表节点 * 节点指针);
    void 列表节点_追加(列表节点 * 列表节点, 三元节点 * 待追加节点指针);
基本表达式节点 * 解析器_创建基本表达式节点(单词信息体 当前单词);

// 节点美化打印
void 解析器_声明前缀打印(FILE * 输出文件, 三元节点 * 节点指针);
void 解析器_语句前缀打印(FILE * 输出文件, 三元节点 * 节点指针);
void 解析器_表达式前缀打印(FILE * 输出文件, 三元节点 * 节点指针);
void 解析器_表达式中缀打印(FILE * 输出文件, 三元节点 * 节点指针);

// LL(1) 表达式解析;
// 三元节点 * 表达式_解析();
三元节点 * 赋值表达式_解析();
三元节点 * 条件表达式_解析();
三元节点 * 二元表达式_解析(uint8_t 优先级);
三元节点 * 一元表达式_解析();
三元节点 * 后缀表达式_解析();
三元节点 * 后缀运算符_解析(三元节点 * 后缀表达式节点指针);
三元节点 * 基本表达式_解析();

// 声明、语句 节点

// 基础结构解析
三元节点 * 标识符列表_解析();
三元节点 * 表达式列表_解析();
三元节点 * 形参列表_解析();
    三元节点 * 形参声明_解析();

三元节点 * 常量表达式列表_解析(); //常数表达式，结果为数字
三元节点 * 常量表达式_解析();

// 复杂结构 解析
// 三元节点 * 文件_解析();

三元节点 * 包声明_解析();
三元节点 * 导入声明_解析();
    三元节点 * 导入描述_解析();

三元节点 * 声明区_解析();
三元节点 * 访问修饰声明_解析();
三元节点 * 声明_解析();
三元节点 * 类型声明_解析();
    三元节点 * 类型描述_解析();
    三元节点 * 类型表达式_解析();
        三元节点 * 指针类型_解析();
        三元节点 * 数组类型_解析();
        三元节点 * 结构体类型_解析();
        三元节点 * 共用体类型_解析();
            三元节点 * 访问修饰字段_解析();
            三元节点 * 字段_解析();
        三元节点 * 枚举体类型_解析();
            三元节点 * 枚举成员_解析();

    三元节点 * 常量声明_解析();
        三元节点 * 常量描述_解析();
    三元节点 * 变量声明_解析();
        三元节点 * 变量描述_解析();
    // void 宏声明_解析();
    三元节点 * 过程声明_解析();
    三元节点 * 函数声明_解析();
        签名节点 * 签名_解析();
    // void 类声明_解析();
    // void 函数声明_解析();
    // void 算符声明_解析();

三元节点 * 语句行_解析();
三元节点 * 语句块_解析();
三元节点 * 语句组_解析();
三元节点 * 语句_解析();
    三元节点 * 标号语句_解析();
    三元节点 * 转到语句_解析();
    三元节点 * 中止语句_解析();
    三元节点 * 继续语句_解析();
    三元节点 * 善后语句_解析();
    三元节点 * 返回语句_解析();
    // 分支
    三元节点 * 如果语句_解析();
    三元节点 * 匹配语句_解析();
    三元节点 * 模式语句_解析();
    三元节点 * 分支语句_解析();
    // 循环
    三元节点 * 当循环语句_解析();
    三元节点 * 循环语句_解析();
    三元节点 * 原始循环三元控制块_解析();
    三元节点 * 对于循环语句_解析();

static uint8_t 二元中缀优先级表[] = {
    // 2 赋值运算符 := 、+= -= *= ·= ×= /= ÷= %= 、<<= >>= &= ∧= |= ∨= ^= ⊕= 右结合
    [冒等于]=2, [加等于]=2, [减等于]=2,
    [星等于]=2, [叉乘等于]=2, [斜杠等于]=2, [除等于]=2, [百分等于]=2,
    [双小于等于]=2, [双大于等于]=2, [与等于]=2, [逻辑与等于]=2, [竖线等于]=2, [逻辑或等于]=2,
    [杨抑等于]=2, [异或等于]=2,
    // 3 条件运算符 ?:  右结合
    [如果]=3,
    // 4 逻辑OR：|| ∨ 
    [双竖线]=4, [逻辑或]=4,
    // 5 逻辑AND：&& ∧
    [双与号]=5, [逻辑与]=5,
    // 6 位或OR：|
    [竖线]=6,
    // 7 位异或XOR：^
    [杨抑号]=7,
    // 8 位与AND：&
    [与号]=8,
    // 9 判等 = != ≠
    [等于号]=9, [感叹等于]=9, [不等于号]=9,
    // 10 比较 < <= ≤ > >= ≥
    [小于号]=10, [小于等于]=10, [小于等于号]=10, [大于号]=10, [大于等于]=10, [大于等于号]=10,
    // 11 移位运算符：<<  >>
    [双小于]=11, [双大于]=11,
    // 12 加减法运算符：+ -
    [加号]=12, [减号]=12,
    // 13 乘除模运算符：* · ×  / ÷  %
    [星号]=13, [叉乘号]=13, [斜杠]=13, [除号]=13, [百分号]=13, [取模号]=13,
};
// static uint8_t 一元前缀优先级表[] = {
//     // 14 一元前缀运算符：! ￢ ¬ 按位取反~ + - 解引用* 取地址& sizeof _Alignof 右结合
//     [感叹号]=14, [逻辑非]=14, [波浪号]=14, /* [加号]=14, [减号]=14, [星号]=14, */ [与号]=14, 
//     [求尺寸]=14,
// };
// static uint8_t 一元后缀优先级表[] = {
//     // 15 后缀运算符：[] () . -> (类型名称){列表}  左结合
//     [左方括号]=15, [右方括号]=15, [左圆括号]=15, [右圆括号]=15, [实心句号]=15, [单线右单箭头]=15,
// };
/******************************************************************************
 * 语法分析器：每次从“词法分析器”获取一个“单词”，解析构建 语法树 和 抽象语法树
 * 
 *****************************************************************************/
FILE * 输入文件_语法分析;
单词信息体 当前单词;
// 单词信息体 下一单词; LL(2)文法改造使用

// 过滤 无效单词、注释、续行符，更新 “当前单词”信息体
单词信息体 读入下一单词() {
    单词信息体 新单词信息体;
    // 掠过无用的 注释、空单词、续行符
    do{
        新单词信息体 = 文件_扫描单词(输入文件_语法分析);
    }while(新单词信息体.类型==注释 || 新单词信息体.类型==空单词
            || 新单词信息体.类型==续行符 || 新单词信息体.错误==无效单词);
    if (当前单词.错误 == 没有错误) {
        当前单词 = 新单词信息体;
    }else {
        fprintf(stderr, "单词扫描错误:");
    }
    return 新单词信息体;
}
// 错误处理：当遇到错误时，跳过部分语句的解析，而不是全部停止

/******************************************************************************
 *                                 文件解析
 *****************************************************************************/
//《文件》：《包声明》 "\n"* 《导入声明》?  \n*  ( 《声明》? "\n")*  文件结束
三元节点 * 文件_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(文件_节点, NULL, NULL, NULL);
    // 读入第一个单词
    读入下一单词();
    // 包声明
    if (当前单词.类型==包) {
        节点->左指针 = 包声明_解析();
    }else {
        fprintf(stderr, "《文件》 源码文件必须以 包声明开头\n");
    }
    while (当前单词.类型==换行) { //略过空行
        读入下一单词();
    }
    // 可选 单个 导入声明
    if (当前单词.类型==导入) {
        节点->中指针 = 导入声明_解析();
    }
    while (当前单词.类型==换行) { //略过空行
        读入下一单词();
    }
    // 《声明区》
    节点->右指针 = 声明区_解析();
    while (当前单词.类型==换行) { //略过空行
        读入下一单词();
    }
    // 文件结束
    if (当前单词.类型!=文件结束) {
        fprintf(stderr, "《文件》：《声明区》后有其它内容，可能是残缺的过程或函数中的语句\n");
    }
    return 节点;
}

// 《包声明》： package保留词 标识符
三元节点 * 包声明_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(未知_节点, NULL, NULL, NULL);
    if (当前单词.类型 == 包) {
        读入下一单词();
        节点->类型 = 包声明_节点;
        if (当前单词.类型==标识符) {
            节点->左指针 = 基本表达式_解析();
        } else {
            fprintf(stderr, "《包声明》 缺少 包名\n");
        }
    } else {
        fprintf(stderr, "《包声明》 缺少引导词 包/package \n");
    }
    return 节点;
}

// 《导入声明》： import 《导入描述》 | "(" (《导入描述》? \n|;)* ")"
三元节点 * 导入声明_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(未知_节点, NULL, NULL, NULL);
    // import
    if (当前单词.类型 == 导入) {
        读入下一单词();
        节点->类型 = 导入声明_节点;
    }else {
        fprintf(stderr, "《导入声明》 缺少 导入/import 引导词\n");
    }
    //单行《导入声明》：import 《导入描述》
    if (当前单词.类型==标识符 || 当前单词.类型==字符串字面量) {
        节点->左指针 = 导入描述_解析();
    }
    //批量《导入声明》："(" (《导入描述》? \n|;)* ")" )
    else if (当前单词.类型==左圆括号) {
        读入下一单词();
        列表节点 * 列表节点 = 解析器_创建列表节点(导入描述组_节点);
        三元节点 * 类型描述节点;
        节点->左指针 = (三元节点*)列表节点;
        while (当前单词.类型!=右圆括号) {
            // 非空行
            if (!(当前单词.类型==换行||当前单词.类型==分号)) {
                类型描述节点 = 导入描述_解析();
                列表节点_追加(列表节点, 类型描述节点);
            }
            读入下一单词(); //读取 行结束符
        }
        if(当前单词.类型==右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《导入描述组》 需要以 右圆括号) 结束\n");
        }
    }else {
        fprintf(stderr, "《导入声明》 引导词 类型/type 后应当为 标识符 或 ( 导入描述组 )\n");
    }
    return 节点;
}

//《导入描述》：《别名:标识符/空标识符》? 《导入路径:字符串》
三元节点 * 导入描述_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(导入描述_节点, NULL, NULL, NULL);
    if (当前单词.类型==标识符 || 当前单词.类型==空标识符) {
        节点->左指针 = 基本表达式_解析();
    }
    if (当前单词.类型 == 字符串字面量) {
        节点->右指针 = 基本表达式_解析(); 
    }else {
        fprintf(stderr, "《导入描述》 应当由 可选别名、导入路径:字符串 组成\n");
    }
    return 节点;
}

/******************************************************************************
 *                                 表达式列表
 *****************************************************************************/
// 《表达式列表》：《表达式》 ((","|"、") 《表达式》)*
三元节点 * 表达式列表_解析() {
    三元节点 * 当前节点 = 表达式_解析();
    列表节点 * 列表节点 = 解析器_创建列表节点(表达式列表_节点);
    列表节点_追加(列表节点, 当前节点);
    while (当前单词.类型==逗号 || 当前单词.类型==顿号) { //《参数列表》尾 (,|、 《赋值表达式》)*
        读入下一单词();
        当前节点 = 表达式_解析(); //创建新《赋值表达式》节点
        列表节点_追加(列表节点, 当前节点);
    }
    return (三元节点*)列表节点;
}

/******************************************************************************
 *                                 常数表达式列表
 *****************************************************************************/
// 《常量表达式列表》: 《常数表达式》((","|"、") 《常量表达式》)*
三元节点 * 常量表达式列表_解析() {
    三元节点 * 当前节点 = 常量表达式_解析();
    列表节点 * 列表节点 = 解析器_创建列表节点(表达式列表_节点);
    列表节点_追加(列表节点, 当前节点);
    while (当前单词.类型==逗号 || 当前单词.类型==顿号) { //《参数列表》尾 (,|、 《赋值表达式》)*
        读入下一单词();
        当前节点 = 常量表达式_解析(); //创建新《赋值表达式》节点
        列表节点_追加(列表节点, 当前节点);
    }
    return (三元节点*)列表节点;
}

// 《常量表达式》：《表达式》
三元节点 * 常量表达式_解析() {
    三元节点 * 节点 = 表达式_解析();
    // 算出常量值
    return 节点;
}

/******************************************************************************
 *                                 标识符列表
 *****************************************************************************/
// 《标识符列表》： (标识符|空标识符)   (,|、 (标识符|空标识符))*
三元节点 * 标识符列表_解析() {
    三元节点 * 节点;
    列表节点 * 列表节点 = 解析器_创建列表节点(标识符列表_节点);
    // 首标识符
    if(当前单词.类型==标识符 || 当前单词.类型==空标识符) {
        节点 = 基本表达式_解析();
        列表节点_追加(列表节点, 节点);
    }else {
        fprintf(stderr, "《标识符列表》 没有以 标识符 开头\n");
    }
    // 剩余标识符
    while (当前单词.类型==逗号 || 当前单词.类型==顿号) { //《标识符列表尾》 FIRST首符集{"," "、"}
        读入下一单词();
        节点 = 基本表达式_解析();
        列表节点_追加(列表节点, 节点);
    }
    return (三元节点*)列表节点;
}

/******************************************************************************
 *                                   声明
 *****************************************************************************/
// 三元指针节点，通常不使用 中指针
签名节点 * 解析器_创建签名节点(uint8_t 节点类型) {
    签名节点 * 节点 = malloc(sizeof(*节点));
    节点->开始位置 = 当前单词.位置;
    节点->结束位置.行 = 当前单词.位置.行; 
    节点->结束位置.列 = 当前单词.位置.列 + 当前单词.单词切片.长度;
    节点->字节地址 = 当前单词.字节地址;
    // 配置关键数据
    节点->类型 = 节点类型;
    return 节点;
}

// 《声明区》：(《访问修饰声明》? \n)*
三元节点 * 声明区_解析() {
    三元节点 * 临时节点;
    列表节点 * 节点 = 解析器_创建列表节点(声明区_节点);
    while (当前单词.类型==加号||当前单词.类型==减号||当前单词.类型==类型
    ||当前单词.类型==常量||当前单词.类型==变量||当前单词.类型==过程||当前单词.类型==函数||当前单词.类型==换行)
    {
        if (当前单词.类型!=换行) {
            临时节点 = 访问修饰声明_解析();
            列表节点_追加(节点, 临时节点);
        }
        读入下一单词();
    }
    return (三元节点*) 节点;
}

// 《访问修饰声明》：(+|-)? 《声明》
三元节点 * 访问修饰声明_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(未知_节点, NULL, NULL, NULL);
    switch (当前单词.类型){
        case 加号: //访问控制 公开 public
            读入下一单词(); 
            节点 = 声明_解析(节点);
            节点->访问修饰 = 公开;
            break;
        case 减号: //访问控制 私有 private
            读入下一单词(); 
            节点 = 声明_解析(节点);
            节点->访问修饰 = 私有;
            break;
        // 《声明》首符集: macro type const let var proc func class
        case 宏: case 类型: case 常量: case 变量: case 设:
        case 过程: case 类: case 函数: case 算符:
            节点 = 声明_解析(节点);
            节点->访问修饰 = 默认;
            break;
        default:
            fprintf(stderr, "《访问修饰声明》 声明没有以 正号+ 负号- 或声明提示词开头\n");
            break;
        }
    return 节点;
}

//《默认声明》：《宏声明》 |《类型声明》 |《常量声明》 |《变量声明》
//           |《过程声明》 |《函数声明》 |《类声明》 |《算符声明》
三元节点 * 声明_解析() {
    三元节点 * 节点;
    switch (当前单词.类型) {
    // 《默认声明》 首符集
    // case 宏:   宏声明_解析();   break;
    case 类型: 节点 = 类型声明_解析(); break;
    case 常量: 节点 = 常量声明_解析(); break;
    case 变量: 节点 = 变量声明_解析(); break;
    case 过程: 节点 = 过程声明_解析(); break;
    case 函数: 节点 = 函数声明_解析(); break;
    // case 类:    类声明_解析(); break;
    // case 算符: 算符声明_解析(); break;
    default:
        // 报错
        break;
    }
    return 节点;
}

/******************************************************************************
 *                                 常量声明
 *****************************************************************************/
// 《常量声明》：const (《常量描述》 | "(" (《常量描述》? \n|;)* ")")
三元节点 * 常量声明_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(未知_节点, NULL, NULL, NULL);
    // const
    if (当前单词.类型 == 常量) {
        读入下一单词();
        节点->类型 = 常量声明_节点;
    }else {
        fprintf(stderr, "《常量声明》 缺少 常量/const 引导词\n");
    }
    //单行《常量声明》：const 《常量描述》
    if (当前单词.类型==标识符) {
        节点->左指针 = 常量描述_解析();
    }
    //批量《常量声明》："(" (《常量描述》? \n|;)* ")" )
    else if (当前单词.类型==左圆括号) {
        读入下一单词();
        列表节点 * 列表节点 = 解析器_创建列表节点(常量描述组_节点);
        三元节点 * 类型描述节点;
        节点->左指针 = (三元节点*)列表节点;
        while (当前单词.类型!=右圆括号) {
            // 非空行
            if (!(当前单词.类型==换行||当前单词.类型==分号)) {
                类型描述节点 = 常量描述_解析();
                列表节点_追加(列表节点, 类型描述节点);
            }
            读入下一单词(); //读取 行结束符
        }
        if(当前单词.类型==右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《类型描述组》 需要以 右圆括号) 结束\n");
        }
    }else {
        fprintf(stderr, "《类型声明》 引导词 类型/type 后应当为 标识符 或 ( 类型描述组 )\n");
    }
    return 节点;
}

// 《常量描述》：《标识符列表》 (《类型表达式》? =|:= 《常量表达式列表》)?    随符集: ;|\n
三元节点 * 常量描述_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(常量描述_节点, NULL, NULL, NULL);
    if (当前单词.类型==标识符) {
        节点->左指针 = 标识符列表_解析();
    }else {
        fprintf(stderr, "《类型描述》 应当以 标识符 开始\n");
    }
    // 《类型表达式》
    switch(当前单词.类型) {
        // 《类型表达式》?
        case 数据型: case 逻辑型: case 标识符:
        case 自然型: case 自然型8: case 自然型16: case 自然型32: case 自然型64:
        case 整型: case 整型8: case 整型16: case 整型32: case 整型64:
        case 浮点: case 浮点32: case 浮点64:
        case 字符: case 字符8: case 字符16: case 字符32: case ascii字符:
        case 单线右单箭头: case 左方括号:
        case 结构体: case 共用体: case 枚举体:
            节点->中指针 = 类型表达式_解析();
        // 《类型表达式》? =|:= 《常量表达式列表》
            if (当前单词.类型==换行 || 当前单词.类型==分号) {
                break;
            }
        case 等于号: case 冒等于:
            读入下一单词();
            节点->右指针 = 常量表达式列表_解析();
            break;
        case 换行: case 分号:
            break;
        default:
            fprintf(stderr, "《常量描述》 标识符后只能是 类型 或 赋值\n");
            break;
    }
    return 节点;
}

/******************************************************************************
 *                                 变量声明
 *****************************************************************************/
// 《变量声明》：var 《变量描述》 | "(" (《变量描述》? \n|;)* ")"
三元节点 * 变量声明_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(未知_节点, NULL, NULL, NULL);
    // var
    if (当前单词.类型 == 变量) {
        读入下一单词();
        节点->类型 = 变量声明_节点;
    }else {
        fprintf(stderr, "《变量声明》 缺少 变量/var 引导词\n");
    }
    //单行《变量声明》：var 《常量描述》
    if (当前单词.类型==标识符) {
        节点->左指针 = 变量描述_解析();
    }
    //批量《变量声明》："(" (《变量描述》? \n|;)* ")" )
    else if (当前单词.类型==左圆括号) {
        读入下一单词();
        列表节点 * 列表节点 = 解析器_创建列表节点(变量描述组_节点);
        三元节点 * 类型描述节点;
        节点->左指针 = (三元节点*)列表节点;
        while (当前单词.类型!=右圆括号) {
            // 非空行
            if (!(当前单词.类型==换行||当前单词.类型==分号)) {
                类型描述节点 = 变量描述_解析();
                列表节点_追加(列表节点, 类型描述节点);
            }
            读入下一单词(); //读取 行结束符
        }
        if(当前单词.类型==右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《类型描述组》 需要以 右圆括号) 结束\n");
        }
    }else {
        fprintf(stderr, "《类型声明》 引导词 类型/type 后应当为 标识符 或 ( 类型描述组 )\n");
    }
    return 节点;
}

// 《变量描述》:《标识符列表》 (《类型表达式》 (赋值号 《常量表达式列表》)? | 赋值号 《常量表达式列表》)
三元节点 * 变量描述_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(变量描述_节点, NULL, NULL, NULL);
    if (当前单词.类型==标识符) {
        节点->左指针 = 标识符列表_解析();
    }else {
        fprintf(stderr, "《类型描述》 应当以 标识符 开始\n");
    }
    // 《类型表达式》 (赋值号 《常量表达式列表》)? 
    switch(当前单词.类型) {
        // 《类型表达式》?
        case 数据型: case 逻辑型: case 标识符:
        case 自然型: case 自然型8: case 自然型16: case 自然型32: case 自然型64:
        case 整型: case 整型8: case 整型16: case 整型32: case 整型64:
        case 浮点: case 浮点32: case 浮点64:
        case 字符: case 字符8: case 字符16: case 字符32: case ascii字符:
        case 单线右单箭头: case 左方括号: // 《构造类型》
        case 结构体: case 共用体: case 枚举体:
            节点->中指针 = 类型表达式_解析();
        // 变量不初始化，随符集 \n ;
            if (当前单词.类型==换行 || 当前单词.类型==分号) {
                break;
            }
        // 变量初始化
        case 等于号: case 冒等于:
            读入下一单词();
            节点->右指针 = 常量表达式列表_解析();
            break;
        default:
            fprintf(stderr, "《变量描述》 变量 标识符 后应当指明类型，或者初始化赋值\n");
            break;
    }
    return 节点;
}

/******************************************************************************
 *                                 类型声明
 *****************************************************************************/
//《类型声明》：type (《类型描述》| "(" (《类型描述》? \n|;)* ")" )
三元节点 * 类型声明_解析() {
    三元节点 * 节点;
    //type
    if (当前单词.类型 == 类型) {
        读入下一单词();
        节点 = 解析器_创建三元节点(类型声明_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《类型声明》 缺少 类型/type 引导词\n");
    }
    //《类型声明》：type 《类型描述》
    if (当前单词.类型==标识符) {
        节点->左指针 = 类型描述_解析();
    }
    //《类型声明》："(" (《类型描述》? \n|;)* ")" )
    else if (当前单词.类型==左圆括号) {
        读入下一单词();
        列表节点 * 列表节点 = 解析器_创建列表节点(类型描述组_节点);
        三元节点 * 类型描述节点;
        节点->左指针 = (三元节点*)列表节点;
        while (当前单词.类型!=右圆括号) {
            // 非空行
            if (!(当前单词.类型==换行||当前单词.类型==分号)) {
                类型描述节点 = 类型描述_解析();
                列表节点_追加(列表节点, 类型描述节点);
            }
            读入下一单词(); //读取 行结束符
        }
        if(当前单词.类型==右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《类型描述组》 需要以 右圆括号) 结束\n");
        }
    }else {
        fprintf(stderr, "《类型声明》 引导词 类型/type 后应当为 标识符 或 ( 类型描述组 )\n");
    }
    return 节点;
}

bool 属于基本类型名首符集(单词类型 单词类型) {
    switch(单词类型) {
    // 《类型描述》 首符集
    case 数据型: case 逻辑型:
    case 自然型: case 自然型8: case 自然型16: case 自然型32: case 自然型64:
    case 整型: case 整型8: case 整型16: case 整型32: case 整型64:
    case 浮点: case 浮点32: case 浮点64:
    case 字符: case 字符8: case 字符16: case 字符32: case ascii字符:
        return true;
    default:
        return false;
        break;
    }
}
bool 属于构造类型名首符集(单词类型 单词类型) {
    switch(单词类型) {
    case 单线右单箭头:
    case 左方括号:
    case 结构体: case 共用体: case 枚举体:
        return true;
    default:
        return false;
        break;
    }
} 
bool 属于类型描述首符集(单词类型 单词类型) {
    switch(单词类型) {
    // 《类型描述》 首符集
    case 数据型: case 逻辑型:
    case 自然型: case 自然型8: case 自然型16: case 自然型32: case 自然型64:
    case 整型: case 整型8: case 整型16: case 整型32: case 整型64:
    case 浮点: case 浮点32: case 浮点64:
    case 字符: case 字符8: case 字符16: case 字符32: case ascii字符:
    case 单线右单箭头:
    case 左方括号:
    case 结构体: case 共用体: case 枚举体:
        return true;
    default:
        return false;
        break;
    }
}

// 《类型描述》：标识符 《类型表达式》   随符集 \n|;
三元节点 * 类型描述_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(类型描述_节点, NULL, NULL, NULL);
    if (当前单词.类型==标识符) {
        节点->左指针 = 基本表达式_解析();
    }else {
        fprintf(stderr, "《类型描述》 应当以 标识符 开始\n");
    }
    // 《类型表达式》
    节点->右指针 = 类型表达式_解析();
    return 节点;
}

/*《基本类型名》: 逻辑型|数据型  | 过程型|函数型
                |自然型|自然型8|自然型16|自然型32|自然型64
                |整型|整型8|整型16|整型32|整型64
				| 浮点 | 浮点32 | 浮点64 
				| 字符 | 字符8 | 字符16 | 字符32 | ascii字符  */ 
// 《构造类型描述》：《指针类型描述》|《数组类型描述》|《结构体描述》|《共用体描述》|《枚举体描述》
static uint8_t 单词类型_数据类型节点表[] = {
    [数据型]=数据型_节点, [逻辑型]=逻辑型_节点,
    [浮点]=浮点_节点, [浮点32]=浮点32_节点, [浮点64]=浮点64_节点,
    [自然型]=自然型_节点, [自然型8]=自然型8_节点, [自然型16]=自然型16_节点, [自然型32]=自然型32_节点, [自然型64]=自然型64_节点,
    [整型]=整型_节点, [整型8]=整型8_节点, [整型16]=整型16_节点, [整型32]=整型32_节点, [整型64]=整型64_节点,
    [字符]=字符_节点, [字符8]=字符8_节点, [字符16]=字符16_节点, [字符32]=字符32_节点, [ascii字符]=ascii字符_节点,
    [标识符]=自定义类型_节点, [过程]=过程类型_节点, [函数]=函数类型_节点,
};
// 《类型表达式》：《基本类型》|《构造类型》|标识符:自定义类型
三元节点 * 类型表达式_解析() {
    三元节点 * 节点;
    // 《类型表达式》
    switch(当前单词.类型) {
        // 《基本类型》
        case 过程: case 函数:
        case 数据型: case 逻辑型: // data bool uint uint8 uint16 uint32 uint64
        case 自然型: case 自然型8: case 自然型16: case 自然型32: case 自然型64:
        case 整型: case 整型8: case 整型16: case 整型32: case 整型64:
        case 浮点: case 浮点32: case 浮点64: //float float32 float64
        case 字符: case 字符8: case 字符16: case 字符32: case ascii字符: //char char8 char16 char32
            节点 = 解析器_创建三元节点(单词类型_数据类型节点表[当前单词.类型], NULL, NULL, NULL);
            读入下一单词();
            break;
        // 《构造类型》 ->x  [4]int  []int   struct{}  union{}  enum{}
        case 单线右单箭头: //指针类型
            节点 = 指针类型_解析();
            break;
        case 左方括号:   //数组类型
            节点 = 数组类型_解析();
            break;
        case 结构体:
            节点 = 结构体类型_解析();
            break;
        case 共用体:
            节点 = 共用体类型_解析();
            break;
        case 枚举体:
            节点 = 枚举体类型_解析();
            break;
        case 标识符: //自定义类型，支持泛型，例如 Vector《user》
            节点 = 解析器_创建三元节点(单词类型_数据类型节点表[当前单词.类型], NULL, NULL, NULL);
            节点->左指针 = (三元节点*)基本表达式_解析();
            break;
        default:
            fprintf(stderr, "《类型描述》 不明《类型表达式》起始符号\n");
            break;
        }
    return 节点;
}

// 《指针类型》： "->" 《类型表达式》
三元节点 * 指针类型_解析() {
    三元节点 * 节点;
    if (当前单词.类型==单线右单箭头) {
        // 动作
        读入下一单词();
        节点 = 解析器_创建三元节点(指针类型_节点, NULL, NULL, NULL);
        节点->左指针 = 类型表达式_解析();
    }else {
        fprintf(stderr, "《指针类型描述》 应当以单线右箭头 -> / → 开头\n");
    }
    return 节点;
}

// 《数组类型》："["《数组长度》"]" 《类型表达式》    《数组长度》：《常量表达式》
三元节点 * 数组类型_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(未知_节点, NULL, NULL, NULL);
    if (当前单词.类型==左方括号) {
        读入下一单词();
        if (当前单词.类型!=右方括号) { //静态数组
            节点->类型 = 数组类型_节点;
            节点->右指针 = 常量表达式_解析();
            if (当前单词.类型==右方括号) {
                读入下一单词();
            }else {
                fprintf(stderr, "《数组类型》 缺少右方括号 ] \n");
            }
            节点->左指针 = 类型表达式_解析();
        }else{
            fprintf(stderr, "《数组类型》 没有指定 数组容量 \n");
        }
    }else {
        // 报错
    }
    return 节点;
}

// 《结构体类型》：struct "{" (《访问修饰字段》? ,|、|\n)* "}"
三元节点 * 结构体类型_解析() {
    列表节点 * 节点;
    if (当前单词.类型==结构体) {
        读入下一单词();
        节点 = 解析器_创建列表节点(结构体类型_节点);
    }else {
        fprintf(stderr, "《结构体类型》 必须以 结构体/struct 引导词开始\n");
    }
    if (当前单词.类型==左花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《结构体类型》 引导词后缺少 左花括号{ \n");
    }
    // (《访问修饰字段》? ,|、|\n)* 首符集 + - 标识符 空行\n
    三元节点 * 字段节点;
    while (当前单词.类型==加号 ||当前单词.类型==减号 ||当前单词.类型==标识符 ||当前单词.类型==换行) {
        if (当前单词.类型!=换行) { //非空行
            字段节点 = 访问修饰字段_解析();
            列表节点_追加(节点, 字段节点);
            if (当前单词.类型==逗号 || 当前单词.类型==顿号 || 当前单词.类型==换行) {
                读入下一单词();
            }else {
                fprintf(stderr, "《结构体类型》 字段间缺少分隔符，可用逗号','、顿号'、'、和换行 进行分隔\n");
            }
        }else if (当前单词.类型==换行){
            读入下一单词();
        }else {
            // 空项警告
            读入下一单词();
        }
    }
    if (当前单词.类型==右花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《结构体类型》 结尾缺少 右花括号} \n");
    }
    return (三元节点*)节点;
}

// 《共用体描述》：union "{" (《访问修饰字段》? ,|、|\n)* "}"
三元节点 * 共用体类型_解析() {
    列表节点 * 节点;
    if (当前单词.类型==共用体) {
        读入下一单词();
        节点 = 解析器_创建列表节点(共用体类型_节点);
    }else {
        fprintf(stderr, "《共用体类型》 必须以 共用体/union 引导词开始\n");
    }
    if (当前单词.类型==左花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《共用体类型》 引导词后缺少 左花括号{ \n");
    }
    // (《访问修饰字段》? ,|、|\n)* 首符集 + - 标识符 空行\n
    三元节点 * 字段节点;
    while (当前单词.类型==加号 ||当前单词.类型==减号 ||当前单词.类型==标识符 ||当前单词.类型==换行) {
        if (当前单词.类型!=换行) { //非空行
            字段节点 = 访问修饰字段_解析();
            列表节点_追加(节点, 字段节点);
            if (当前单词.类型==逗号 || 当前单词.类型==顿号 || 当前单词.类型==换行) {
                读入下一单词();
            }else {
                fprintf(stderr, "《共用体类型》 字段间缺少分隔符，可用逗号','、顿号'、'、和换行 进行分隔\n");
            }
        }else if (当前单词.类型==换行){
            读入下一单词();
        }else {
            // 空项警告
            读入下一单词();
        }
    }
    if (当前单词.类型==右花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《共用体类型》 结尾缺少 右花括号} \n");
    }
    return (三元节点*)节点;
}

// 《访问修饰字段》：(+|-)? 《字段》
三元节点 * 访问修饰字段_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(字段_节点, NULL, NULL, NULL);
    switch (当前单词.类型){
        case 加号: //访问控制 公开 public
            节点->访问修饰 = 公开;
            读入下一单词(); 
            节点 = 字段_解析(节点);
            break;
        case 减号: //访问控制 私有 private
            节点->访问修饰 = 私有;
            读入下一单词(); 
            节点 = 字段_解析(节点);
            break;
        // 《字段》首符 标识符
        case 标识符:
            节点->访问修饰 = 默认;
            节点 = 字段_解析(节点);
            break;
        default:
            fprintf(stderr, "《访问修饰字段》 声明没有以 正号'+'、负号'-' 标识符 开头\n");
            break;
        }
    return 节点;
}

// 《字段》：标识符 《类型表达式》
三元节点 * 字段_解析(三元节点 * 节点) {
    if (当前单词.类型==标识符) {
        节点->左指针 = 基本表达式_解析();
        节点->右指针 = 类型表达式_解析();
    }else {
        fprintf(stderr, "《字段》 可能没有以标识符开头\n");
    }
    return 节点;
}

// 《枚举体类型》： enum "{" (《枚举成员》? ,|\n)* "}"
三元节点 * 枚举体类型_解析() {
    列表节点 * 节点;
    if (当前单词.类型==枚举体) {
        读入下一单词();
        节点 = 解析器_创建列表节点(枚举体类型_节点);
    }else {
        fprintf(stderr, "《枚举体类型》 必须以 共用体/enum 引导词开始\n");
    }
    if (当前单词.类型==左花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《枚举体类型》 引导词后缺少 左花括号{ \n");
    }
    // (《枚举成员》? ,|、|\n)*
    三元节点 * 字段节点;
    while (当前单词.类型==标识符 ||当前单词.类型==换行) {
        if (当前单词.类型!=换行) { //非空行
            字段节点 = 枚举成员_解析();
            列表节点_追加(节点, 字段节点);
            if (当前单词.类型==逗号 || 当前单词.类型==顿号 || 当前单词.类型==换行) {
                读入下一单词();
            }else {
                fprintf(stderr, "《枚举体类型》 字段间缺少分隔符，可用逗号','、顿号'、'、和换行 进行分隔\n");
            }
        }else if (当前单词.类型==换行){
            读入下一单词();
        }else {
            // 空项警告
            读入下一单词();
        }
    }
    if (当前单词.类型==右花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《枚举体类型》 结尾缺少 右花括号} \n");
    }
    return (三元节点*)节点;
}

// 《枚举成员》：标识符 (":="|"=" 《枚举值》)?   《枚举值》：《常量表达式》
三元节点 * 枚举成员_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(枚举成员_节点, NULL, NULL, NULL);
    if(当前单词.类型==标识符) {
        节点->左指针 = (三元节点*)基本表达式_解析(); // 枚举成员名
        if(当前单词.类型==等于号 || 当前单词.类型==冒等于) {//(":="|"=" 常数:枚举值)
            读入下一单词();
            节点->右指针 = 常量表达式_解析();
        }
    }else{
        fprintf(stderr, "《枚举成员》 没有以 标识符 开头\n");
    }
    return 节点;
}

/******************************************************************************
 *                                 过程、方法、函数 声明
 *****************************************************************************/
// 《形参列表》： 《参数声明》  ( ","|"、" 《参数声明》)*
三元节点 * 形参列表_解析() {
    列表节点 * 节点 = 解析器_创建列表节点(形参列表_节点);
    三元节点 * 临时节点;
    // 首形参
    临时节点 = 形参声明_解析();
    列表节点_追加(节点, 临时节点);
    // 其它形参
    while (当前单词.类型==逗号 || 当前单词.类型==顿号) {
        读入下一单词();
        临时节点 = 形参声明_解析();
        列表节点_追加(节点, 临时节点);
    }
    return (三元节点*)节点;
}

// 《参数声明》：标识符? 《类型表达式》
三元节点 * 形参声明_解析() {
    三元节点 * 节点 = 解析器_创建三元节点(形参声明_节点, NULL, NULL, NULL);
    if (当前单词.类型==标识符) {
        节点->左指针 = 基本表达式_解析();
    }
    节点->右指针 = 类型表达式_解析();
    return 节点;
}

// 《过程声明》：proc "("《形参声明》")"?  标识符 "("《形参列表》?")" ("("《形参列表》")" | 《类型表达式》)? 《语句块》 
三元节点 * 过程声明_解析() {
    三元节点 * 节点;
    if(当前单词.类型==过程) {
        节点 = 解析器_创建三元节点(过程声明_节点, NULL, NULL, NULL);
        读入下一单词();
    }
    // 《过程签名》
    if(当前单词.类型==左圆括号 || 当前单词.类型==标识符) { //过程名
        节点->左指针 = (三元节点*)签名_解析();
    }else {
        fprintf(stderr, "《过程声明》 引导词后应当是 绑定形参声明 或 过程名\n");
    }
    // 定义体
    if (当前单词.类型==左花括号) {
        节点->右指针 = 语句块_解析();
    }else {
        fprintf(stderr, "《过程声明》 过程签名后应当是 左花括号{ 开头的过程定义\n");
    }
    return 节点;
}

// 《函数声明》：func 标识符 "(" 《参数列表》 ")"   ("(" 《参数列表》 ")")  《语句块》
三元节点 * 函数声明_解析() {
    三元节点 * 节点;
    if(当前单词.类型==函数) {
        节点 = 解析器_创建三元节点(函数声明_节点, NULL, NULL, NULL);
        读入下一单词();
    }
    // 《函数签名》
    if(当前单词.类型==左圆括号 || 当前单词.类型==标识符) { //绑定形参 / 函数名
        节点->左指针 = (三元节点*)签名_解析();
    }else {
        fprintf(stderr, "《函数声明》 引导词后应当是 绑定形参声明 或 函数名\n");
    }
    // 定义体
    if (当前单词.类型==左花括号) {
        节点->右指针 = 语句块_解析();
    }else {
        fprintf(stderr, "《函数声明》 函数签名后应当是 左花括号{ 开头的过程定义\n");
    }
    return 节点;
}

// 《签名》：( "("标识符:绑定名 《类型表达式》")" )?  函数名:标识符 "(" 《形参列表》? ")" ("("《形参列表》")" | 《类型表达式》)?
签名节点 * 签名_解析() {
    签名节点 * 节点 = 解析器_创建签名节点(签名_节点);
    if (当前单词.类型==左圆括号) {
        读入下一单词();
        节点->前指针 = 形参声明_解析();
        if (当前单词.类型 == 右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《签名》 绑定形参缺少右圆括号)\n");
        }
    }
    if (当前单词.类型==标识符) {
        节点->左指针 = 基本表达式_解析();
    }else {
        fprintf(stderr, "《签名》 缺少过程名/函数名\n");
    }
    // 形参列表
    if (当前单词.类型 == 左圆括号) {
        读入下一单词();
        if (当前单词.类型!= 右圆括号) {
            节点->中指针 = 形参列表_解析();
        }
        if (当前单词.类型==右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《签名》 形参列表缺少右圆括号)\n");
        }
    }
    // 返回值列表
    if (当前单词.类型 != 左花括号) { //非空
        if (当前单词.类型==左圆括号) {
            节点->右指针 = 形参列表_解析();
            if (当前单词.类型==右圆括号) {
                读入下一单词();
            }else {
                fprintf(stderr, "《签名》 返回值列表 缺少右圆括号)\n");
            }
        }else {
            节点->右指针 = 类型表达式_解析();
        }
    }
    return 节点;
}

/******************************************************************************
 *                                    语句
 *****************************************************************************/
// 三元指针节点，通常不使用 中指针
三元节点 * 解析器_创建三元节点(uint8_t 节点类型, 三元节点* 左指针, 三元节点* 中指针, 三元节点* 右指针) {
    三元节点 * 节点 = malloc(sizeof(*节点));
    节点->开始位置 = 当前单词.位置;
    节点->结束位置.行 = 当前单词.位置.行; 
    节点->结束位置.列 = 当前单词.位置.列 + 当前单词.单词切片.长度;
    节点->字节地址 = 当前单词.字节地址;
    // 配置关键数据
    节点->类型 = 节点类型;
    节点->访问修饰 = 默认;
    节点->左指针 = (三元节点*)左指针;
    节点->中指针 = (三元节点*)中指针;
    节点->右指针 = (三元节点*)右指针;
    return 节点;
}

// 《语句块》："{" (《语句》?  \n|;)* "}"
三元节点 * 语句块_解析() {
    列表节点 * 列表节点;
    三元节点 * 节点;
    if (当前单词.类型==左花括号) {
        读入下一单词();
        列表节点 = 解析器_创建列表节点(语句块_节点);
    }else {
        fprintf(stderr, "《语句块》没有以 左花括号\"{\" 开始\n");
    }
    while (!(当前单词.类型==右花括号 || 当前单词.类型==文件结束)) { //《语句组》位于《语句块》中，随符集为 右边缘界符 "}"
        switch(当前单词.类型) { // 《语句》 FIRST首符集？
            case 宏: case 类型: case 常量: case 变量: //《声明》
            case 标识符: case 空标识符:
            case 转到: case 中止: case 继续: 
            case 如果: case 匹配:
            case 循环: case 当: case 对于:
            case 善后: case 返回:  //《语句》 FIRST首符集，继续
                节点 = 语句_解析();
                列表节点_追加(列表节点, 节点);
                if (当前单词.类型==换行 || 当前单词.类型==分号) {
                    读入下一单词();
                }else {
                    fprintf(stderr, "《语句行》 没有以 换行\"\\n\"或分号\";\" 结束\n");
                }
                break;
            case 标号: case 竖线: // 《标号语句》《模式语句》 可以与其它语句同一行
                节点 = 语句_解析();
                列表节点_追加(列表节点, 节点);
                if (当前单词.类型==换行 || 当前单词.类型==分号) {
                    读入下一单词();
                }
                break;
            case 左花括号: //嵌套《语句块》
                节点 = (三元节点*)语句块_解析();
                列表节点_追加(列表节点, 节点);
                break;
            case 换行: case 分号: //《空行》，直接是 换行"\n" 或 分号";"
                读入下一单词();
                break;
            default:
                fprintf(stderr, "《语句块》不明首单词\n");
                break;
            }
    }
    if (当前单词.类型==右花括号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《语句块》 没有以 右花括号\"}\" 结束\n");
    }
    return (三元节点*)列表节点;
}
/*《语句》：《声明》|《简单语句》|《标签语句》|《goto语句》|《break语句》|《continue语句》 
		|《branch语句》|《if语句》|《while语句》|《loop语句》|《for语句》
		|《defer语句》|《return语句》|《语句块》   */
三元节点 * 语句_解析() {
    三元节点 * 节点;
    switch(当前单词.类型) { // 《语句行》 FIRST首符集？
        // case 宏:    宏声明_解析(); break;
        // case 类型: 类型声明_解析(); break;
        case 常量: 节点 = 常量声明_解析(); break;
        case 变量: 节点 = 变量声明_解析(); break;
        case 设: case 值:
            break;
        //以标识符、算符开头的语句
        case 标识符: case 空标识符:
            节点 = 表达式_解析();   break;
        case 左花括号: 节点 = 语句块_解析(); break;
        // 基本流程控制
        case 标号: 节点 = 标号语句_解析(); break;
        case 转到: 节点 = 转到语句_解析(); break;
        case 中止: 节点 = 中止语句_解析(); break;
        case 继续: 节点 = 继续语句_解析(); break;
        case 善后: 节点 = 善后语句_解析(); break;
        case 返回: 节点 = 返回语句_解析(); break;
        // 分支语句
        case 如果: 节点 = 如果语句_解析(); break;
        case 匹配: 节点 = 匹配语句_解析(); break;
        case 竖线: 节点 = 模式语句_解析(); break;
        // case 分支: 节点 = 分支语句_解析(); break;
        // 循环语句
        case 当:   节点 = 当循环语句_解析(); break;
        case 循环: 节点 = 循环语句_解析();   break;
        case 对于: 节点 = 对于循环语句_解析(); break;
        default:
            fprintf(stderr, "《语句》不明语句首单词\n");
            break;;
        }
    // 理论上应该检查 随符集，但是由于 goto 转到语句 可以在任何语句之前 而太过麻烦
    return 节点;
}

// 《if语句》：if《表达式》 《语句块》 (else 《语句块》|《if语句》)?
三元节点 * 如果语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型 == 如果) {
        读入下一单词();
    }else {
        fprintf(stderr, "如果 分支语句没有以 if 开始");
    }
    三元节点 * 条件表达式节点 = 表达式_解析();
    节点 = 解析器_创建三元节点(如果_节点, 条件表达式节点, NULL, NULL);
    节点->中指针 = 语句块_解析();
    if (当前单词.类型 == 否则) { //if《表达式》 《裸语句块》 else 《裸语句块》|《if语句》
        节点->类型 = 如果否则_节点;
        读入下一单词();
        if (当前单词.类型==如果) { //if《表达式》 《裸语句块》 else 《if语句》
            节点->右指针 = 如果语句_解析();
        }else if (当前单词.类型==左花括号) { //if《表达式》 《裸语句块》 else 《裸语句块》
            节点->右指针 = 语句块_解析();
        }else {
            fprintf(stderr, "《如果语句》 否则/else 后跟非法单词\n");
        }
    }
    return 节点;
}

// 《match语句》：match 《表达式》 《语句块》
三元节点 * 匹配语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==匹配) {
        读入下一单词();
        节点 = 解析器_创建三元节点(匹配_节点, NULL, NULL, NULL);
    } else {
        fprintf(stderr, "《匹配语句》 没有以 匹配/match 开头\n");
    }
    节点->左指针 = 表达式_解析();
    节点->右指针 = 语句块_解析();
    return 节点;
}

// 《模式语句》："|" 《表达式列表》 ":"    初始版本采用类型switch的查表法，不过采用二分查找
三元节点 * 模式语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==竖线) {
        读入下一单词();
        节点 = 解析器_创建三元节点(模式_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《模式语句》 没有以 或竖线 | 开始\n");
    }
    节点->左指针 = 表达式列表_解析();
    if (当前单词.类型 == 冒号) {
        读入下一单词();
    }else {
        fprintf(stderr, "《模式语句》 缺少结尾冒号 :\n");
    }
    return 节点;
}

// 《while语句》："while" 《表达式》《语句块》
三元节点 * 当循环语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==当) {
        读入下一单词();
        节点 = 解析器_创建三元节点(当循环_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《当循环》 没有以 当/while 开头\n");
    }
    节点->左指针 = 表达式_解析();
    if (当前单词.类型==左花括号) {
        节点->右指针 = 语句块_解析();
    }else {
        fprintf(stderr, "《当循环》 表达式后缺少以左花括号{ 开始的《语句块》\n");
    }
    return 节点;
}

// 《循环语句》：循环 《原始循环三元控制块》 《语句块》 | 循环 《语句块》 (直到 《表达式》)?
三元节点 * 循环语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==循环) {
        读入下一单词();
    }else {
        fprintf(stderr, "《循环语句》 没有以 循环 开头\n");
    }
    if (当前单词.类型==左花括号) { // 循环 《语句块》 直到 《表达式》
        节点 = 解析器_创建三元节点(直到循环_节点, NULL, NULL, NULL);
        节点->左指针 = 语句块_解析();
        if (当前单词.类型==直到) { //直到循环比死循环更常见
            读入下一单词();
            节点->右指针 = 表达式_解析();
        }else {
            if (当前单词.类型==换行 || 当前单词.类型==分号) {
                节点->类型 = 死循环_节点;
            }else {
                fprintf(stderr, "《直到循环》 语句块后应当结束，或者是 直到/until \n");
            }
        }
    }else {                      // 循环 《原始循环三元控制块》《语句块》
        节点 = 解析器_创建三元节点(原始循环_节点, NULL, NULL, NULL);
        节点->左指针 = 原始循环三元控制块_解析();
        节点->右指针 = 语句块_解析();
    }
    return 节点;
}

// 《原始循环三元控制块》：《初始化表达式》? ;|\n 《逻辑值表达式》? ;|\n 《后处理表达式》
三元节点 * 原始循环三元控制块_解析() {
    三元节点 * 节点;
    节点 = 解析器_创建三元节点(原始循环三元控制块_节点, NULL, NULL, NULL);
    节点->左指针 = 表达式_解析();
    if (当前单词.类型==分号 || 当前单词.类型==换行) {
        读入下一单词();
    }else {
        fprintf(stderr, "《原始循环三元控制块》 控制块中必须使用 分号; 或换行 分隔\n");
    }
    节点->中指针 = 表达式_解析();
    if (当前单词.类型==分号 || 当前单词.类型==换行) {
        读入下一单词();
    }else {
        fprintf(stderr, "《原始循环三元控制块》 控制块中必须使用 分号; 或换行 分隔\n");
    }
    节点->右指针 = 表达式_解析();
    // 随符集检查
    if (当前单词.类型!=左花括号) {
        fprintf(stderr, "《原始循环三元控制块》 控制块后必须是以 左花括号{ 开头的《语句块》\n");
    }
    return 节点;
}

// 《for语句》：for 《原始循环三元控制块》 《语句块》
三元节点 * 对于循环语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型 == 对于) {
        读入下一单词();
        节点 = 解析器_创建三元节点(原始循环_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《for循环》 必须以 对于/for 开头\n");
    }
    节点->左指针 = 原始循环三元控制块_解析();
    节点->右指针 = 语句块_解析();
    return 节点;
}

// 《label语句》："label" 标识符 ":"
三元节点 * 标号语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==标号) { //《标号语句》："label"
        读入下一单词();
        节点 = 解析器_创建三元节点(标号_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《标号语句》 没有以 标号/label 开始\n");
    }
    if (当前单词.类型 == 标识符) { //《标号语句》："label" 标识符
        节点->左指针 = 基本表达式_解析();
    }else {
        fprintf(stderr, "《标号语句》 标号/label 后必须是 标识符\n");
    }
    if (当前单词.类型==冒号) { //《标号语句》："label" 标识符 ":"
        读入下一单词();
    }else {
        fprintf(stderr, "《标号语句》 标号名 后缺失冒号 \":\"\n");
    }
    return 节点;
}
// 《goto语句》： "goto"  标识符
三元节点 * 转到语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==转到) {
        读入下一单词();
        节点 = 解析器_创建三元节点(转到_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《转到语句》 没有以 转到/goto 开头\n");
    }
    if (当前单词.类型 == 标识符) { //《标号语句》："label" 标识符
        节点->左指针 = (三元节点*)解析器_创建基本表达式节点(当前单词);
        读入下一单词();
    }else {
        fprintf(stderr, "《转到语句》 转到/goto 后必须是 标识符\n");
    }
    return 节点;
}

// 《break语句》： "break" 标识符?
三元节点 * 中止语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==中止) {
        读入下一单词();
        节点 = 解析器_创建三元节点(中止_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《中止语句》 没有以 中止/break 开头\n");
    }
    if (当前单词.类型==标识符) {
        节点->左指针 = 基本表达式_解析();
    } else if (当前单词.类型==换行 || 当前单词.类型==分号 || 当前单词.类型==右花括号) {
    }else {
        fprintf(stderr, "《中止语句》 应当以 换行 或 分号 结尾\n");
    }
    return 节点;
}

// 《continue语句》： "continue" 标识符?
三元节点 * 继续语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==继续) {
        读入下一单词();
        节点 = 解析器_创建三元节点(继续_节点, NULL, NULL, NULL);
    }else {
        fprintf(stderr, "《中止语句》 没有以 中止/break 开头\n");
    }
    if (当前单词.类型==标识符) {
        节点->左指针 = 基本表达式_解析();
    } else if (当前单词.类型==换行 || 当前单词.类型==分号 || 当前单词.类型==右花括号) {
    }else {
        fprintf(stderr, "《中止语句》 应当以 换行 或 分号 结尾\n");
    }
    return 节点;
}

// 《defer语句》：   defer保留词  《表达式》
三元节点 * 善后语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==善后) {
        节点 = 解析器_创建三元节点(善后_节点, NULL, NULL, NULL);
        读入下一单词();
    }else {
        fprintf(stderr, "《善后语句》 没有以 善后/defer 开头\n");
    }
    节点->左指针 = 表达式_解析();
    return 节点;
}

// 《return语句》：  return保留词  《表达式列表》?
三元节点 * 返回语句_解析() {
    三元节点 * 节点;
    if (当前单词.类型==返回) {
        节点 = 解析器_创建三元节点(返回_节点, NULL, NULL, NULL);
        读入下一单词();
    }else {
        fprintf(stderr, "《返回语句》 没有以 返回/return 开头\n");
    }
    if (!(当前单词.类型==分号 || 当前单词.类型==换行 || 当前单词.类型==文件结束)) { //《返回语句》随符集 \n ;
        节点->左指针 = 表达式列表_解析();
    }
    return 节点;
}


/******************************************************************************
 *                             表达式 LL(1)优先级分析
 * 基本表达式 >> 后缀表达式 >> 一元表达式 >> 二元表达式 >> 条件表达式 >> 赋值表达式
 *****************************************************************************/
// 《表达式》首符集 if 标识符 前缀运算符& + - ~ ! ￢ ¬

// 《表达式列表》 节点初始化
列表节点 * 解析器_创建列表节点(节点类型 类型) {
    列表节点 * 列表节点 = malloc(sizeof(*列表节点));
    列表节点->开始位置 = 当前单词.位置;
    列表节点->结束位置.行 = 当前单词.位置.行; 
    列表节点->结束位置.列 = 当前单词.位置.列 + 当前单词.单词切片.长度;
    列表节点->字节地址 = 当前单词.字节地址;
    // 配置关键数据
    列表节点->类型 = 类型;
    列表节点->长度 = 0;
    列表节点->容量 = 8; //通常函数参数的个数在8个以内，常见的在4个以内
    列表节点->数据区 = (三元节点**)malloc((列表节点->容量)*sizeof(三元节点*));
    return 列表节点;
}

// 《表达式列表》 扩容，翻倍扩容
void 列表节点_扩容(列表节点 * 节点指针) {
    int 新容量 = 节点指针->容量 * 2; //翻倍扩容
    三元节点 * 新数据区;
    新数据区 = realloc(节点指针->数据区, 新容量 * sizeof(三元节点*));
    // realloc失败检查
    if (新数据区 == NULL) {
        fprintf(stderr, "列表节点 扩容 内存分配失败！\n");
    }
    // 更新容量和数据区指针
    节点指针->容量 = 新容量;
    节点指针->数据区 = (三元节点**)新数据区;
}
// 《表达式列表》 追加一个节点
void 列表节点_追加(列表节点 * 列表节点, 三元节点 * 待追加节点指针) {
    // 检查扩容
    int 新长度 = 列表节点->长度 + 1;
    if (新长度 > (列表节点->容量)) {
        列表节点_扩容(列表节点);
    }
    // 然后添加节点指针
    (列表节点->数据区)[新长度-1] = 待追加节点指针;
    // 最后更新长度
    列表节点->长度 = 新长度;
}


// 通用 《基本表达式》 节点
基本表达式节点 * 解析器_创建基本表达式节点(单词信息体 当前单词) {
    基本表达式节点 * 节点 = malloc(sizeof(*节点));
    节点->开始位置 = 当前单词.位置;
    节点->结束位置.行 = 当前单词.位置.行;
    节点->结束位置.列 = 当前单词.位置.列 + 当前单词.单词切片.长度;
    节点->字节地址 = 当前单词.字节地址;
    switch (当前单词.类型) {
        case 标识符:
            节点->类型 = 标识符_节点;
            节点->值.标识符 = 当前单词.字面值.标识符;
            break;
        case 空标识符:
            节点->类型 = 空标识符_节点;
            break;
        case 逻辑值字面量:
            节点->类型 = 逻辑值字面量_节点;
            节点->值.逻辑值 = 当前单词.字面值.逻辑值;
            break;
        case 整数字面量:
            节点->类型 = 整数字面量_节点;
            节点->值.整数 = 当前单词.字面值.整数;
            break;
        case 浮点数字面量:
            节点->类型 = 浮点数字面量_节点;
            节点->值.浮点数 = 当前单词.字面值.浮点数;
            break;
        case 字符字面量:
            节点->类型 = 字符字面量_节点;
            节点->值.字符 = 当前单词.字面值.字符;
            break;
        case 字符串字面量:
            节点->类型 = 字符串字面量_节点;
            节点->值.字符串 = 当前单词.字面值.字符串;
            break;
        default:
            // 报错
            break;
        }
    return 节点;
}

static uint8_t 单词类型_二元表达式节点类型表[] = {
    // 赋值运算符 := 、+= -= *= ·= ×= /= ÷= %= 、<<= >>= &= ∧= |= ∨= ^= ⊕=
    [冒等于]=赋值_节点,
    [加等于]=加赋值_节点, [减等于]=减赋值_节点,
    [星等于]=乘赋值_节点, [叉乘等于]=乘赋值_节点, [中间点等于]=乘赋值_节点,
    [斜杠等于]=除赋值_节点, [除等于]=除赋值_节点, [百分等于]=模赋值_节点,
    [双小于等于]=位左移赋值_节点, [双大于等于]=位右移赋值_节点,
    [与等于]=与赋值_节点, [逻辑与等于]=与赋值_节点, [竖线等于]=或赋值_节点, [逻辑或等于]=或赋值_节点,
    [杨抑等于]=异或赋值_节点, [异或等于]=异或赋值_节点,
    // 算数运算符 + - * · × / ÷
    [加号]=加法_节点, [减号]=减法_节点,
    [星号]=乘法_节点, [中间点]=乘法_节点, [叉乘号]=乘法_节点,
    [斜杠]=除法_节点, [除号]=除法_节点, [百分号]=取模_节点, [取模号]=取模_节点,
    // 比较运算符 = != ≠ < <= ≤ > >= ≥
    [等于号]=等于_节点, [感叹等于]=不等于_节点, [不等于号]=不等于_节点,
    [小于号]=小于_节点, [小于等于]=小于等于_节点, [小于等于号]=小于等于_节点,
    [大于号]=大于_节点, [大于等于]=大于等于_节点, [大于等于号]=大于等于_节点,
    // 位运算符、逻辑运算符。具体效果由操作数的类型决定，逻辑型/整数型
    // << >> && ||     & ∧ | ∨ ^ ⊕
    [双小于] = 位左移_节点, [双大于] = 位右移_节点,
    [双与号] = 短路与_节点, [双竖线] = 短路或_节点,
    [与号] = 与_节点, [逻辑与] = 与_节点, [竖线] = 或_节点, [逻辑或] = 或_节点,
    [杨抑号] = 异或_节点, [逻辑异或] = 异或_节点,
};

// 《表达式》:= 《赋值表达式》 | 《条件表达式》
三元节点 * 表达式_解析() {
    三元节点 * 节点;
    if (当前单词.类型 == 如果) {
        节点 = 条件表达式_解析();
    }else {
        节点 = 赋值表达式_解析();
    }
    return 节点;
}

// 注意：这里无法通过首符集区分，因此合并不进行区分。错误留给 语义分析 处理
/* 《赋值表达式》:= 《二元表达式》
                | 《一元表达式》《赋值运算符》 《条件表达式》|《二元表达式》 */ 
三元节点 * 赋值表达式_解析() {
    //合并为 《赋值表达式》:=《二元表达式》 ( 《赋值运算符》 (《条件表达式》|《二元表达式》) )?
    三元节点 * 节点;
    节点 = 二元表达式_解析(4);
    if (二元中缀优先级表[当前单词.类型]==二元中缀优先级表[冒等于]) { //《赋值运算符》，优先级为2
        节点 = 解析器_创建三元节点(单词类型_二元表达式节点类型表[当前单词.类型], 节点, NULL, NULL);
        读入下一单词();
        if (当前单词.类型==如果) { //《条件表达式》
            节点->右指针 = 条件表达式_解析();
        }else {                  // 《二元表达式》
            节点->右指针 = 二元表达式_解析(4);
        }   
    }else { // 简单的 《二元运算符》，仅用于向上传递中转
        // 《赋值表达式》随符集 , 、 ) 《表达式随符集》 ) ]  条件表达式"else"  { 语句分隔符 ; \n 文件结束符
        switch (当前单词.类型) {
        case 逗号: case 冒号: case 右圆括号: case 右方括号: case 否则: case 左花括号:
        case 分号: case 换行: case 文件结束:
            // 正常结束
            break;
        default:
            fprintf(stderr, "《赋值表达式》 随符集匹配失败\n");
            break;
        }
    }
    return 节点;
}

// 《条件表达式》:= if 《二元表达式》 then 《表达式》 (else 《条件表达式》|《二元表达式》)?
三元节点 * 条件表达式_解析() {
    三元节点 * 节点;
    // if 《二元表达式》
    if (当前单词.类型==如果) {
        读入下一单词();
        // 《二元表达式》
        节点 = 解析器_创建三元节点(条件表达式_节点, NULL, NULL, NULL);
        节点->左指针 = 二元表达式_解析(4);
    }else {
        fprintf(stderr, "《条件表达式》 没有以“如果”/if 开头\n");
    }
    // then 《表达式》
    if (当前单词.类型==则) {
        读入下一单词();
        节点->中指针 = 表达式_解析();
        // (else 《条件表达式》|《二元表达式》)?
        if (当前单词.类型==否则) {
            读入下一单词();
            if (当前单词.类型==如果) { //嵌套 else 《条件表达式》
                节点->右指针 = 条件表达式_解析();
            }else { // else 《二元表达式》
                // 《二元表达式》首符集 前缀运算符 sizeof ( 标识符 各种字面量
                switch (当前单词.类型){
                case 与号: case 加号: case 减号: case 波浪号: case 感叹号: case 逻辑非:
                case 求尺寸: case 左圆括号:
                case 标识符: case 空标识符:
                case 逻辑值字面量: case 整数字面量: case 浮点数字面量:
                case 字符字面量: case 字符串字面量:
                    节点->右指针 = 二元表达式_解析(4);
                    break;
                default:
                    fprintf(stderr, "《条件表达式》 否则《表达式》首符集匹配失败\n");
                    break;
                }
            }
        }else {
            fprintf(stderr, "《条件表达式》 没有 \"则 / then\" 分隔词\n");
        }
    }
    // (else 《条件表达式》)? 
    switch (当前单词.类型) {
        // else 《条件表达式》
        case 否则:
            读入下一单词();
            节点->右指针 = 条件表达式_解析();
            break;
        // if 《二元表达式》 then 《表达式》
        // 《条件表达式》随符集: , 、 ) ] : 语句分隔符 ; \n 文件结束符 EOF
        case 逗号: case 冒号:
        case 右圆括号: case 右方括号:
        case 分号: case 换行:
        case 文件结束:
        // 合并《赋值表达式》:=《二元表达式》(《赋值运算符》《赋值表达式》)?  产生多余随符集《赋值运算符》
        case 冒等于: case 加等于: case 减等于:
        case 星等于: case 叉乘等于: case 斜杠等于: case 除等于: case 百分等于:
        case 双小于等于: case 双大于等于:
        case 与等于: case 逻辑与等于: case 竖线等于: case 逻辑或等于: case 杨抑等于: case 异或等于:
            break;
        default:
            fprintf(stderr, "《条件表达式》 随符集 匹配失败\n");
            break;
        }
    return 节点;
}

// 《二元运算符》:= + - * × / ÷ %   = != ≠ < <= ≤ > >= ≥   << >> & | ^ ∧ ∨ ⊕
// 《二元表达式》:= 《一元表达式》 (《二元运算符》 《一元表达式》)*   注意：这里不包括“赋值”
三元节点 * 二元表达式_解析(uint8_t 优先级) {
    三元节点 *节点; //从对应的优先级开始，逐级向上处理
    // 《一元表达式》 解析
    switch (当前单词.类型) {
        // 《一元表达式》首符集 前缀运算符 sizeof ( 标识符 字面量
        case 与号: case 加号: case 减号: case 波浪号: case 感叹号: case 逻辑非:
        case 左圆括号: case 求尺寸:
        case 标识符: case 空标识符: 
        case 逻辑值字面量: case 整数字面量: case 浮点数字面量:
        case 字符字面量: case 字符串字面量:
            节点 = 一元表达式_解析();
            break;
        default:
            fprintf(stderr, "《二元表达式》解析错误: 《一元表达式》首符集匹配失败\n");
            break;
        }
    // 探测二元运算符的存在
    switch (当前单词.类型){
        // 《二元运算符》首符集
        case 加号: case 减号: case 星号: case 叉乘号:
        case 斜杠: case 除号: case 百分号: case 取模号:
        case 等于号: case 感叹等于: case 不等于号:
        case 小于号: case 小于等于: case 小于等于号:
        case 大于号: case 大于等于: case 大于等于号:
        case 双与号: case 双竖线: case 与号: case 逻辑与: case 竖线: case 逻辑或: 
        case 双小于: case 双大于:case 杨抑号: case 逻辑异或:
            for (int 目标优先级=二元中缀优先级表[当前单词.类型]; 目标优先级>优先级; 目标优先级--) {
                while (二元中缀优先级表[当前单词.类型]==目标优先级) {
                    // 左结合，先由左操作数和运算符构建节点，然后补充右操作数
                    节点 = 解析器_创建三元节点(单词类型_二元表达式节点类型表[当前单词.类型], 节点, NULL, NULL);
                    读入下一单词();
                    节点->右指针 = 二元表达式_解析(目标优先级-1); //递归解析 右节点
                }
            }
            break;
        // 《二元表达式》随符集: then else { , 、) ] :语句分隔符; \n 文件结束符 
        case 则: case 否则: case 左花括号:
        case 逗号: case 顿号: case 冒号:
        case 右圆括号: case 右方括号:
        case 换行: case 分号: case 文件结束:
        // 合并《赋值表达式》:=《二元表达式》(《赋值运算符》《赋值表达式》)?  产生多余随符集《赋值运算符》
        case 冒等于: case 加等于: case 减等于:
        case 星等于: case 叉乘等于: case 斜杠等于: case 除等于: case 百分等于:
        case 双小于等于: case 双大于等于:
        case 与等于: case 逻辑与等于: case 竖线等于: case 逻辑或等于: case 杨抑等于: case 异或等于:
            break;
        default:
            fprintf(stderr, "《二元表达式》: 不明二元运算符 / 随符集匹配失败\n");
            break;
        }
    return 节点;
}
static uint8_t 单词类型_前缀表达式节点类型表[] = {
    // 《前缀运算符》 & + - ~ ! ￢ ¬
    [与号]   = 取地址_节点, [加号]   = 取正_节点, 
    [减号]   = 取负_节点,   [波浪号] = 位取反_节点, 
    [感叹号] = 非_节点,     [逻辑非] = 非_节点,
};

//《前缀运算符》:= & + - ~ ! ￢ ¬
//《一元表达式》:=《前缀运算符》《一元表达式》 |sizeof ( (《类型描述》|《一元表达式》) ) |《后缀表达式》
三元节点 * 一元表达式_解析() {
    三元节点 * 表达式节点;
    switch (当前单词.类型) {
    // 《一元表达式》:= 《前缀运算符》《一元表达式》
    case 与号: case 加号: case 减号: case 波浪号:  
    case 感叹号: case 逻辑非:
        表达式节点 = 解析器_创建三元节点(单词类型_前缀表达式节点类型表[当前单词.类型], NULL, NULL, NULL);
        读入下一单词();
        表达式节点->左指针 = 一元表达式_解析();
        break;
    // 《后缀表达式》="("《表达式》")" | "(" (《赋值表达式》 ((","|"、") 《赋值表达式》)* )? ")"
    case 左圆括号:
        读入下一单词();
        // 《后缀表达式》="("《表达式》")"
        表达式节点 = 表达式_解析();
        // 调用运算符 "(" (《赋值表达式》 ((","|"、") 《赋值表达式》)* )? ")"
        // ##########
        if (当前单词.类型==右圆括号) {
            读入下一单词();
        }else {
            fprintf(stderr, "《强制类型转换》/\"(《表达式》)\" 缺失右圆括号\")\"\n");
        }
        break;
    // 《一元表达式》:= "sizeof" "(" (《类型描述》|《一元表达式》) ")"
    case 求尺寸: 
        读入下一单词();
        表达式节点 = 解析器_创建三元节点(取尺寸_节点, NULL, NULL, NULL);
        if (当前单词.类型==左圆括号) {
            读入下一单词();
        } else {
            fprintf(stderr, "《一元表达式》 sizeof 后没有括号\n");
            // 报错
        }
        // 《类型描述》 | 《一元表达式》
        switch(当前单词.类型) {
            // 《类型描述》 首符集
            case 数据型: case 逻辑型:
            case 自然型: case 自然型8: case 自然型16: case 自然型32: case 自然型64:
            case 整型: case 整型8: case 整型16: case 整型32: case 整型64:
            case 浮点: case 浮点32: case 浮点64:
            case 字符: case 字符8: case 字符16: case 字符32: case ascii字符:
            case 单线右单箭头:
            case 左方括号:
            case 结构体: case 共用体: case 枚举体:
                // 表达式节点 = 解析器_创建表达式节点(取尺寸_节点, 类型描述_解析(), NULL, NULL);
                break;
            // 《一元表达式》首符集
            case 逻辑值字面量: case 整数字面量: case 浮点数字面量: case 字符字面量: case 字符串字面量:
            case 标识符: case 左圆括号:
            case 与号: case 加号: case 减号: case 波浪号: case 感叹号: case 逻辑非:
                表达式节点->左指针 = 一元表达式_解析();
            default:
                // 报错
                break;
            }
        if (当前单词.类型==右圆括号) {
            读入下一单词();
        } else {
            // 报错
        }
        break;
    // 《一元表达式》:= 《后缀表达式》
    case 标识符: case 空标识符:
    case 逻辑值字面量: case 整数字面量: case 浮点数字面量: 
    case 字符字面量: case 字符串字面量:
        表达式节点 = 后缀表达式_解析();
        break;
    default:
        fprintf(stderr, "《一元表达式》首符集 匹配失败\n");
        break;
    }
    return 表达式节点;
}

// 《后缀表达式》:= 《基本表达式》 《后缀运算符》*
三元节点 * 后缀表达式_解析() {
    三元节点 * 左节点;
    // 《基本表达式》
    switch (当前单词.类型){
        case 标识符: case 空标识符:
        case 逻辑值字面量:
        case 整数字面量: case 浮点数字面量:
        case 字符字面量: case 字符串字面量:
            左节点 = 基本表达式_解析();
            break;
        default:
            break;
        }
    // 放弃《后缀表达式》随符集的检查，因为在 [《表达式》] 和 调用() 中的潜在随符集冲突
    //有 《后缀运算符》* 点. 调用() 下标[] 类型转换as 解引用-> 递增递减++ -- 的尺寸 的类型
    while (当前单词.类型==实心句号 || 当前单词.类型==中间点 || 当前单词.类型==左圆括号 || 当前单词.类型==左方括号
        || 当前单词.类型==当作 || 当前单词.类型== 单线右单箭头
        || 当前单词.类型==双加号||当前单词.类型==双减号||当前单词.类型==的尺寸||当前单词.类型==的类型)
    {
        左节点 = 后缀运算符_解析(左节点); //左子树 向 右上 逐级递升，每级添加一个后缀运算符
    }
    return 左节点;
}

/* 《后缀运算符》:= "[" 《表达式》 "]" | "(" 《表达式列表》? ")"
				| "."|"·" 标识符 | "as" 《类型描述》 | 的尺寸 | 的类型 | "->" | ++ | --                              */ 
三元节点 * 后缀运算符_解析(三元节点 * 目标节点指针) {
    三元节点 * 后缀运算符节点;
    switch (当前单词.类型) { //设置 节点类型
        case 左方括号: 读入下一单词(); // "[" 《表达式》 "]"
            后缀运算符节点 = 解析器_创建三元节点(下标运算符_节点, 目标节点指针, NULL, NULL);
            后缀运算符节点->右指针 = 表达式_解析();
            if (当前单词.类型==右方括号) {
                读入下一单词();
            }else {
                fprintf(stderr, "《后缀运算符》下标运算符 缺失右方括号 \"]\" \n");
            }
            break;
        case 左圆括号: 读入下一单词(); // "(" 《表达式列表》? ")"
            后缀运算符节点 = 解析器_创建三元节点(调用运算符_节点, 目标节点指针, NULL, NULL);
            if (当前单词.类型 != 右圆括号) { //《参数列表》 非空
                后缀运算符节点->右指针 = 表达式列表_解析();
            }
            if (当前单词.类型==右圆括号) {
                读入下一单词();
            }else {
                // 报错
            }
            break;
        case 实心句号: case 中间点: // "." 标识符
            读入下一单词();
            后缀运算符节点 = 解析器_创建三元节点(点运算符_节点, 目标节点指针, NULL, NULL);
            if (当前单词.类型==标识符) {
                后缀运算符节点->右指针 = 基本表达式_解析();
            } else {
                // 报错
            }
            break;
        case 当作: 读入下一单词(); // "as" 《类型描述》
            后缀运算符节点 = 解析器_创建三元节点(强制类型转换_节点, 目标节点指针, NULL, NULL);
            后缀运算符节点->右指针 = 类型描述_解析();
            break;
        // 简单后缀运算符 "->"、"++"、"--"、的尺寸、的类型
        case 单线右单箭头:
            后缀运算符节点 = 解析器_创建三元节点(解引用_节点, 目标节点指针, NULL, NULL);
            读入下一单词();
            break;
        case 双加号:
            后缀运算符节点 = 解析器_创建三元节点(递增_节点, 目标节点指针, NULL, NULL);
            读入下一单词();
            break;
        case 双减号:
            后缀运算符节点 = 解析器_创建三元节点(递减_节点, 目标节点指针, NULL, NULL);
            读入下一单词();
            break;
        case 的尺寸:
            后缀运算符节点 = 解析器_创建三元节点(取尺寸_节点, 目标节点指针, NULL, NULL);
            读入下一单词();
            break;
        case 的类型:
            后缀运算符节点 = 解析器_创建三元节点(取类型_节点, 目标节点指针, NULL, NULL);
            读入下一单词();
            break;
        default:
            fprintf(stderr, "《后缀运算符》 解析错误!\n");
            break;
        }
    return 后缀运算符节点;
}

// 《基本表达式》:= 标识符|逻辑值字面量|整数字面量|浮点数字面量|字符字面量|字符串字面量| "(" 《表达式》 ")"
三元节点 * 基本表达式_解析() {
    // 解析树
    基本表达式节点 * 节点指针;
    switch (当前单词.类型){
        case 标识符: case 空标识符:
        case 逻辑值字面量:
        case 整数字面量: case 浮点数字面量:
        case 字符字面量: case 字符串字面量:
            节点指针 = 解析器_创建基本表达式节点(当前单词);
            break;
        case 左圆括号: // 《基本表达式》:= "(" 《表达式》 ")"
            读入下一单词();
            节点指针 = (基本表达式节点*)表达式_解析();  //临时调试用
            if (当前单词.类型==右圆括号) {
                读入下一单词();
            }else {
                fprintf(stderr, "《基本表达式》 右圆括号')'错误！\n");
            }
            break;
        default:
            fprintf(stderr, "《基本表达式》 错误！\n");
            break;
        }
    读入下一单词();
    return (三元节点*)节点指针;
}

static char* 节点类型_提示符表[] = {
    // 《声明》
    [包声明_节点]="package", [导入声明_节点]="import",
    [宏声明_节点]="macro",
    [常量声明_节点]="const", [变量声明_节点]="var",
    [过程声明_节点]="proc",  [函数声明_节点]="func",
    // 《类型表达式》
    [数据型_节点]="data", [逻辑型_节点]="bool",
    [自然型_节点]="uint", [自然型8_节点]="uint8", [自然型16_节点]="uint16",
    [自然型32_节点]="uint32", [自然型64_节点]="uint64",
    [整型_节点]="int", [整型8_节点]="int8", [整型16_节点]="int16",
    [整型32_节点]="int32", [整型64_节点]="int64",
    [浮点_节点]="float", [浮点32_节点]="float32", [浮点64_节点]="float64",
    [字符_节点]="char", [字符8_节点]="char8", [字符16_节点]="char16",
    [字符32_节点]="char32", [ascii字符_节点]="ascii",
    [过程类型_节点]="proc", [函数类型_节点]="func",
    // 构造类型
    [指针类型_节点]="->", 
    [结构体类型_节点]="struct", [共用体类型_节点]="union", [枚举体类型_节点]="enum",
    // 声明
    [类型声明_节点]="type", 
    [常量声明_节点]="const", [变量声明_节点]="var",
    // 语句
    [如果_节点]="if", [如果否则_节点]="if_else", [匹配_节点]="match", [模式_节点]="|",
    [当循环_节点]="while", [直到循环_节点]="do_until", [原始循环_节点]="for", [死循环_节点]="loop",
    [标号_节点]="label", [转到_节点]="goto", [中止_节点]="break", [继续_节点]="continue",
    [善后_节点]="defer", [返回_节点]="return",
    // 《赋值运算符》
    [赋值_节点] = ":=",     [加赋值_节点]="+=",      [减赋值_节点]="-=",
    [乘赋值_节点]="*=",      [除赋值_节点]="÷=",     [模赋值_节点]="%=",
    [位左移赋值_节点]="<<=", [位右移赋值_节点]=">>=",
    [与赋值_节点]="&=",      [或赋值_节点]="|=",     [异或赋值_节点]="^=",
    // 《条件运算符》
    [条件表达式_节点] = "if",
    // 《二元运算符》
    [加法_节点] = "+", [减法_节点]    = "-",
    [乘法_节点] = "*", [除法_节点]    = "÷", [取模_节点] = "%",
    [等于_节点] = "=", [不等于_节点]   = "≠", //比较运算符
    [小于_节点] = "<", [小于等于_节点] = "≤", [大于_节点] = ">", [大于等于_节点] = "≥",
    [位左移_节点]="<<", [位右移_节点]=">>",
    [与_节点]="&", [或_节点]="|", [异或_节点]="⊕",
    // 一元表达式 《前缀运算符》
    [取地址_节点]    = "&",  [解引用_节点] = "*", 
    [取正_节点]      = "+",  [取负_节点]  =  "-", 
    [位取反_节点]    = "~",  [非_节点]  =  "¬",
    // 《后缀运算符》 [] () . -> ++ --
    [下标运算符_节点] = "[]",   [调用运算符_节点]   = "()",
    [点运算符_节点]   = ".",    [强制类型转换_节点] = "as",
    [右箭头运算符_节点] = "->", [递增_节点]      = "++",
    [递减_节点]         = "--",
    [取尺寸_节点] = "取尺寸", [取类型_节点] = "取类型",
    // 《基本表达式》
    [空标识符_节点]="_",
};

// 声明 美化打印
int 美化打印_缩进等级 = 0;
void 解析器_声明前缀打印(FILE * 输出文件, 三元节点 * 节点指针) {
    列表节点 * 列表节点指针;
    签名节点 * 签名节点指针;
    // 主体声明
    switch (节点指针->类型) {
    // 《过程声明》 《函数声明》
    case 过程声明_节点: case 函数声明_节点:
        if (节点指针->访问修饰==公开){
            fprintf(输出文件, "+");
        } else if (节点指针->访问修饰==私有) {
            fprintf(输出文件, "-");
        }
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_声明前缀打印(输出文件, 节点指针->左指针); //《签名》
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->右指针); //定义《语句块》
        break;
    // 《签名》
    case 签名_节点:
        签名节点指针 = (签名节点*)节点指针;
        //绑定形参
        if (签名节点指针->前指针 != NULL) {
            fputc('(', 输出文件);
            解析器_声明前缀打印(输出文件, 签名节点指针->前指针);
            fprintf(输出文件, ") ");
        }
        // 过程名
        解析器_表达式前缀打印(输出文件, 签名节点指针->左指针);
        fputc('(', 输出文件);
        if (签名节点指针->中指针 != NULL) { //形参列表非空
            解析器_声明前缀打印(输出文件, 签名节点指针->中指针);
        }
        fputc(')', 输出文件);
        // 返回值
        if (签名节点指针->右指针 != NULL) { //有返回值
            if (签名节点指针->右指针->类型 == 形参列表_节点) { //形参列表，需要括号
                fprintf(输出文件, " (");
                解析器_声明前缀打印(输出文件, 签名节点指针->右指针);
                fputc(')', 输出文件);
            }else { //单《类型表达式》
                fputc(' ', 输出文件);
                解析器_声明前缀打印(输出文件, 签名节点指针->右指针);
            }
        }
        break;
    // 《形参列表》
    case 形参列表_节点:
        列表节点指针 = (列表节点*)节点指针;
        // 打印形参列表
        if (列表节点指针->长度 != 0) { //形参列表不为空
            解析器_声明前缀打印(输出文件, 列表节点指针->数据区[0]);
            for (int i=1; i<列表节点指针->长度; i++) {
                fprintf(输出文件, ", ");
                解析器_声明前缀打印(输出文件, 列表节点指针->数据区[i]);
            }
        }
        break;
    case 形参声明_节点:
        if (节点指针->左指针 != NULL) {
            解析器_表达式前缀打印(输出文件, 节点指针->左指针); // 参数名
            fputc(' ', 输出文件);
        }
        解析器_声明前缀打印(输出文件, 节点指针->右指针); // 类型
        break;
    // 《文件》
    case 文件_节点:
        解析器_声明前缀打印(输出文件, 节点指针->左指针); // 《包声明》
        fprintf(输出文件, "\n\n");
        解析器_声明前缀打印(输出文件, 节点指针->中指针); // 《导入声明》
        fprintf(输出文件, "\n\n");
        解析器_声明前缀打印(输出文件, 节点指针->右指针); // 《声明区》
        fputc('\n', 输出文件);
        break;
    // 《包声明》
    case 包声明_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        break;
    // 《声明区》
    case 声明区_节点:
        列表节点指针 = (列表节点*)节点指针;
        // 打印声明
        if (列表节点指针->长度 != 0) { //声明区不为空
            解析器_声明前缀打印(输出文件, 列表节点指针->数据区[0]);
            for (int i=1; i<列表节点指针->长度; i++) {
                fputc('\n', 输出文件);
                解析器_声明前缀打印(输出文件, 列表节点指针->数据区[i]);
            }
        }
        break;
    // 《导入声明》 《常量声明》 《变量声明》
    case 导入声明_节点: case 常量声明_节点: case 变量声明_节点:
        if (节点指针->访问修饰==公开){
            fprintf(输出文件, "+");
        } else if (节点指针->访问修饰==私有) {
            fprintf(输出文件, "-");
        }
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_声明前缀打印(输出文件, 节点指针->左指针); //《导入描述》 《常量描述》 《变量描述》
        break;
    case 导入描述组_节点: case 常量描述组_节点: case 变量描述组_节点:
        列表节点指针 = (列表节点*)节点指针;
        fprintf(输出文件, "(\n");
        美化打印_缩进等级++;
        // 打印字段组
        if (列表节点指针->长度 != 0) { //字段组不为空
            // 打印第一个描述
            for (int i=0; i<美化打印_缩进等级; i++){ //美化缩进
                fprintf(输出文件, "    ");
            }
            解析器_声明前缀打印(输出文件, 列表节点指针->数据区[0]);
            fputc('\n', 输出文件);
            for (int i=1; i<列表节点指针->长度; i++) {
                for (int i=0; i<美化打印_缩进等级; i++){ //美化缩进
                    fprintf(输出文件, "    ");
                }
                解析器_声明前缀打印(输出文件, 列表节点指针->数据区[i]);
                fputc('\n', 输出文件);
            }
        }
        美化打印_缩进等级--;
        for (int i=0; i<美化打印_缩进等级; i++){
            fprintf(输出文件, "    ");
        }
        fprintf(输出文件, ")");
        break;
    case 常量描述_节点: case 变量描述_节点:
        解析器_声明前缀打印(输出文件, 节点指针->左指针); //《标识符列表》
        if (节点指针->中指针 != NULL) { // 《类型表达式》
            fputc(' ', 输出文件);
            解析器_声明前缀打印(输出文件, 节点指针->中指针); //《类型表达式》
        }
        if (节点指针->右指针 != NULL) { //《常量表达式列表》
            fprintf(输出文件, " = ");
            解析器_表达式前缀打印(输出文件, 节点指针->右指针); //《常量表达式列表》
        }
        break;
    case 导入描述_节点:
        if (节点指针->左指针 != NULL) {
            解析器_表达式前缀打印(输出文件, 节点指针->左指针); //可选《包别名》
            fputc(' ', 输出文件);
        }
        解析器_表达式前缀打印(输出文件, 节点指针->右指针); //《包路径:字符串》
        break;
    // 《类型声明》
    case 类型声明_节点:
        if (节点指针->访问修饰==公开){
            fprintf(输出文件, "+");
        } else if (节点指针->访问修饰==私有) {
            fprintf(输出文件, "-");
        }
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_声明前缀打印(输出文件, 节点指针->左指针); //《类型描述》
        break;
    case 类型描述_节点: // 《类型描述》：标识符 《类型表达式》
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_声明前缀打印(输出文件, 节点指针->右指针);
        break;
    // 《基本数据类型》
    case 过程类型_节点: case 函数类型_节点:
    case 数据型_节点: case 逻辑型_节点:
    case 自然型_节点: case 自然型8_节点: case 自然型16_节点: case 自然型32_节点: case 自然型64_节点:
    case 整型_节点: case 整型8_节点: case 整型16_节点: case 整型32_节点: case 整型64_节点:
    case 浮点_节点: case 浮点32_节点: case 浮点64_节点:
    case 字符_节点: case 字符8_节点: case 字符16_节点: case 字符32_节点: case ascii字符_节点:
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        break;
    case 自定义类型_节点:
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        if (节点指针->右指针 != NULL) { //如果有 类型参数 的话
        }
        break;
    // 《构造数据类型》
    case 指针类型_节点:
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        解析器_声明前缀打印(输出文件, 节点指针->左指针);
        break;
    case 数组类型_节点:
        fputc('[', 输出文件);
        解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        fputc(']', 输出文件);
        解析器_声明前缀打印(输出文件, 节点指针->左指针);
        break;
    case 结构体类型_节点: case 共用体类型_节点:
        列表节点指针 = (列表节点*)节点指针;
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        fprintf(输出文件, "{\n");
        美化打印_缩进等级++;
        // 打印字段组
        if (列表节点指针->长度 != 0) { //字段组不为空
            for (int i=0; i<列表节点指针->长度; i++) {
                for (int i=0; i<美化打印_缩进等级; i++){
                    fprintf(输出文件, "    ");
                }
                解析器_声明前缀打印(输出文件, 列表节点指针->数据区[i]);
                fputc('\n', 输出文件);
            }
        }
        美化打印_缩进等级--;
        for (int i=0; i<美化打印_缩进等级; i++){
            fprintf(输出文件, "    ");
        }
        fprintf(输出文件, "}");
        break;
    case 字段_节点:
        if (节点指针->访问修饰==公开){
            fprintf(输出文件, "+");
        } else if (节点指针->访问修饰==私有) {
            fprintf(输出文件, "-");
        }
        解析器_表达式前缀打印(输出文件, 节点指针->左指针); // 成员名
        fputc(' ', 输出文件);
        解析器_声明前缀打印(输出文件, 节点指针->右指针);   // 成员类型
        break;
    case 枚举体类型_节点:
        列表节点指针 = (列表节点*)节点指针;
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        fprintf(输出文件, "{\n");
        美化打印_缩进等级++;
        // 打印字段组
        if (列表节点指针->长度 >= 0) { //字段组不为空
            for (int i=0; i<列表节点指针->长度; i++) {
                for (int i=0; i<美化打印_缩进等级; i++){
                    fprintf(输出文件, "    ");
                }
                解析器_声明前缀打印(输出文件, 列表节点指针->数据区[i]);
                fputc('\n', 输出文件);
            }
        }
        美化打印_缩进等级--;
        for (int i=0; i<美化打印_缩进等级; i++){
            fprintf(输出文件, "    ");
        }
        fprintf(输出文件, "}");
        break;
    case 枚举成员_节点:
        解析器_表达式前缀打印(输出文件, 节点指针->左指针); //枚举成员名
        if (节点指针->右指针 != NULL) { //可选 枚举值
            fprintf(输出文件, " = ");
            解析器_表达式前缀打印(输出文件, 节点指针->右指针); 
        }
        break;
    // 标识符列表
    case 标识符列表_节点:
        列表节点指针 = (列表节点*)节点指针;
        if (列表节点指针->长度 >= 0) {
            // 打印 第一个标识符
            解析器_表达式前缀打印(输出文件, 列表节点指针->数据区[0]);
            // 剩余标识符
            for (int i=1; i<列表节点指针->长度; i++) {
                fprintf(输出文件, ", ");
                解析器_表达式前缀打印(输出文件, 列表节点指针->数据区[i]);
            }
        }
        break;
    default:
        fprintf(stderr, "《声明前缀打印》：匹配失败\n");
        break;
    }
}

// 语句美化打印
void 解析器_语句前缀打印(FILE * 输出文件, 三元节点 * 节点指针) {
    switch (节点指针->类型) {
    // 循环
    case 死循环_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_语句前缀打印(输出文件, 节点指针->左指针);
        fputc('\n', 输出文件);
        break;
    case 原始循环_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_语句前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->右指针);
        fputc('\n', 输出文件);
        break;
    case 原始循环三元控制块_节点:
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, "; ");
        解析器_表达式前缀打印(输出文件, 节点指针->中指针);
        fprintf(输出文件, "; ");
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        break;
    case 当循环_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->右指针);
        fputc('\n', 输出文件);
        break;
    case 直到循环_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_语句前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        fputc('\n', 输出文件);
        break;
    // 分支语句
    case 如果_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->中指针);
        fputc('\n', 输出文件);
        break;
    case 如果否则_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->中指针);
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->右指针);
        fprintf(输出文件, "\n");
        break;
    case 匹配_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fputc(' ', 输出文件);
        解析器_语句前缀打印(输出文件, 节点指针->右指针);
        fputc('\n', 输出文件);
        break;
    case 模式_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, ":\n");
        break;
    // 基本语句
    case 语句块_节点:
        美化打印_缩进等级++;
        fprintf(输出文件, "{\n");
        列表节点 * 列表节点指针 = (列表节点*)节点指针;
        if (列表节点指针->长度 != 0) { //参数列表不为空
            // 打印美化缩进，每级缩进4个空格
            for (int i=0; i<美化打印_缩进等级; i++){
                fprintf(输出文件, "    ");
            }
            解析器_语句前缀打印(输出文件, 列表节点指针->数据区[0]); //打印首表达式
            for (int i=1; i<列表节点指针->长度; i++) { //剩余表达式
                for (int i=0; i<美化打印_缩进等级; i++){
                    fprintf(输出文件, "    ");
                }
                解析器_语句前缀打印(输出文件, 列表节点指针->数据区[i]);
            }
        }
        // 打印美化缩进，每级缩进4个空格
        美化打印_缩进等级--;
        for (int i=0; i<美化打印_缩进等级; i++){
            fprintf(输出文件, "    ");
        }
        fprintf(输出文件, "}");
        break;
    case 标号_节点: case 转到_节点: case 中止_节点: case 继续_节点: case 善后_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        if (节点指针->左指针 != NULL) {
            解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        }
        fputc('\n', 输出文件);
        break;
    case 返回_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        if (节点指针->左指针 != NULL) {
            解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        }
        fputc('\n', 输出文件);
        break;
    // 《表达式》
    default:
        解析器_表达式前缀打印(输出文件, 节点指针);
        fputc('\n', 输出文件);
        break;
    }
}

// 表达式中缀美化打印 (a) + (b)
void 解析器_表达式中缀打印(FILE * 输出文件, 三元节点 * 节点指针) {
    列表节点 * 列表节点指针;
    switch (节点指针->类型) {
    // 《赋值表达式》
    case 赋值_节点:       case 加赋值_节点:    case 减赋值_节点:
    case 乘赋值_节点:     case 除赋值_节点:    case 模赋值_节点:
    case 位左移赋值_节点: case 位右移赋值_节点:
    case 与赋值_节点:     case 或赋值_节点:    case 异或赋值_节点:
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, " %s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        break;
    // 《条件表达式》
    case 条件表达式_节点:
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        fputc('(', 输出文件);
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, ") then(");
        解析器_表达式中缀打印(输出文件, 节点指针->中指针);
        if (节点指针->右指针!=NULL) {
            fprintf(输出文件, ") else(");
            解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        }else {
            fprintf(stderr, "");
        }
        fputc(')', 输出文件);
        break;
    // 《二元表达式》
    case 加法_节点: case 减法_节点: case 乘法_节点: case 除法_节点: case 取模_节点:
    case 等于_节点: case 不等于_节点:
    case 小于_节点: case 小于等于_节点: case 大于_节点: case 大于等于_节点:
    case 位左移_节点: case 位右移_节点: case 短路与_节点: case 短路或_节点:
    case 与_节点: case 或_节点: case 异或_节点:
        fputc('(', 输出文件);
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fputc(')', 输出文件);
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        fputc('(', 输出文件);
        解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        fputc(')', 输出文件);
        break;
    // 《一元表达式》 & * + - ~ ! ￢ ¬
    case 取地址_节点: case 解引用_节点: case 取正_节点: case 取负_节点:
    case 位取反_节点: case 非_节点:
        fprintf(输出文件, "%s(", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fputc(')', 输出文件);
        break;
    // 《后缀表达式》 简单后缀运算符 ++ -- ->
    case 递增_节点: case 递减_节点: case 右箭头运算符_节点:
    case 取尺寸_节点: case 取类型_节点:
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        break;
    // 《后缀表达式》 复合后缀运算符 x.i x(i,j) x[i]  x 的尺寸 x 的类型
    case 点运算符_节点:
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        break;
    case 下标运算符_节点:
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fputc('[', 输出文件);
        解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        fputc(']', 输出文件);
        break;
    case 调用运算符_节点:
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fputc('(', 输出文件);
        if (节点指针->右指针 != NULL) { //参数列表 非空
            解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        } 
        fputc(')', 输出文件);
        break;
    case 表达式列表_节点:
        列表节点指针 = (列表节点*)节点指针;
        if (列表节点指针->长度 != 0) { //参数列表不为空
            for (int i=0; i<列表节点指针->长度; i++) {
                解析器_表达式中缀打印(输出文件, 列表节点指针->数据区[i]);
                fprintf(输出文件, ", ");
            }
            // 最后抹去多余的 ", "
            fprintf(输出文件, "\b\b");
        }
        break;
    case 强制类型转换_节点:
        解析器_表达式中缀打印(输出文件, 节点指针->左指针);
        fprintf(输出文件, " %s ", 节点类型_提示符表[节点指针->类型]);
        if (节点指针->右指针 != NULL)
            解析器_表达式中缀打印(输出文件, 节点指针->右指针);
        else fprintf(输出文件, "缺省");
        break;
    //《基本表达式》
    case 标识符_节点: unicode切片_文件打印(((基本表达式节点*)节点指针)->值.标识符, 输出文件); break;
    case 空标识符_节点: fprintf(输出文件, "_"); break;
    case 逻辑值字面量_节点: fprintf(输出文件,"%s", ((基本表达式节点*)节点指针)->值.逻辑值==true?"true":"false");
        break;
    case 整数字面量_节点: fprintf(输出文件, "%d", ((基本表达式节点*)节点指针)->值.整数); break;
    case 浮点数字面量_节点: fprintf(输出文件, "%f", ((基本表达式节点*)节点指针)->值.浮点数); break;
    case 字符字面量_节点:
        fputc('\'', 输出文件);
        文件_写入utf8字符(输出文件, unicode转utf8(((基本表达式节点*)节点指针)->值.字符));
        fputc('\'', 输出文件);
        break;
    case 字符串字面量_节点:
        fputc('"', 输出文件);
        unicode切片_文件打印(((基本表达式节点*)节点指针)->值.字符串, 输出文件); 
        fputc('"', 输出文件);
        break;
    default:
        break;
    }
}

// 表达式前缀美化打印 (+  a, b)
void 解析器_表达式前缀打印(FILE * 输出文件, 三元节点 * 节点指针) {
    列表节点 * 列表节点指针;
    switch (节点指针->类型) {
    // 《表达式列表》
    case 表达式列表_节点:
        列表节点指针 = (列表节点*)节点指针;
        if (列表节点指针->长度 != 0) { //参数列表不为空
            解析器_表达式前缀打印(输出文件, 列表节点指针->数据区[0]); //打印首表达式
            for (int i=1; i<列表节点指针->长度; i++) { //剩余表达式
                fprintf(输出文件, ", ");
                解析器_表达式前缀打印(输出文件, 列表节点指针->数据区[i]);
            }
        }
        break;    
    // 《赋值表达式》
    case 赋值_节点:       case 加赋值_节点:    case 减赋值_节点:
    case 乘赋值_节点:     case 除赋值_节点:    case 模赋值_节点:
    case 位左移赋值_节点: case 位右移赋值_节点:
    case 与赋值_节点:     case 或赋值_节点:    case 异或赋值_节点:
        fputc('(', 输出文件); 
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针); fprintf(输出文件, ", ");
        解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        fputc(')', 输出文件);
        break;
    // 《条件表达式》
    case 条件表达式_节点:
        fputc('(', 输出文件);
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针); fprintf(输出文件, ", ");
        解析器_表达式前缀打印(输出文件, 节点指针->中指针);
        if (节点指针->右指针 != NULL) {
            fprintf(输出文件, ", ");
            解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        }
        fputc(')', 输出文件);
        break;
    // 《二元表达式》
    case 加法_节点: case 减法_节点: case 乘法_节点: case 除法_节点: case 取模_节点:
    case 等于_节点: case 不等于_节点:
    case 小于_节点: case 小于等于_节点: case 大于_节点: case 大于等于_节点:
    case 位左移_节点: case 位右移_节点: case 短路与_节点: case 短路或_节点:
    case 与_节点: case 或_节点: case 异或_节点:
        fputc('(', 输出文件);
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针); fprintf(输出文件, ", ");
        解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        fputc(')', 输出文件);
        break;
    // 《一元表达式》 & * + - ~ ! ￢ ¬
    case 取地址_节点: case 解引用_节点: case 取正_节点: case 取负_节点:
    case 位取反_节点: case 非_节点:
        fprintf(输出文件, "%s", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        break;
    // 《后缀表达式》 简单后缀运算符 ++ -- -> 的尺寸 的类型
    case 递增_节点: case 递减_节点: case 右箭头运算符_节点:
    case 取尺寸_节点: case 取类型_节点:
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        break;
    // 《后缀表达式》 复合后缀运算符 x.i x(i,j) x[i]
    case 点运算符_节点: case 下标运算符_节点: case 强制类型转换_节点:
        fputc('(', 输出文件);
        fprintf(输出文件, "%s ", 节点类型_提示符表[节点指针->类型]);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针);
        if (节点指针->右指针 != NULL) {
            fprintf(输出文件, ", ");
            解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        }
        fputc(')', 输出文件);
        break;
    // 调用func  (func 参数列表)
    case 调用运算符_节点:
        fputc('(', 输出文件);
        解析器_表达式前缀打印(输出文件, 节点指针->左指针); //调用过程名
        if (节点指针->右指针 != NULL) {
            解析器_表达式前缀打印(输出文件, 节点指针->右指针);
        }
        fputc(')', 输出文件);
        break;
    // 《表达式》
    case 标识符_节点: unicode切片_文件打印(((基本表达式节点*)节点指针)->值.标识符, 输出文件); 
        break;
    case 空标识符_节点: fprintf(输出文件, "_"); break;
    case 逻辑值字面量_节点: fprintf(输出文件,"%s", ((基本表达式节点*)节点指针)->值.逻辑值==true?"true":"false");
        break;
    case 整数字面量_节点: fprintf(输出文件, "%d", ((基本表达式节点*)节点指针)->值.整数); 
        break;
    case 浮点数字面量_节点: fprintf(输出文件, "%f", ((基本表达式节点*)节点指针)->值.浮点数); 
        break;
    case 字符字面量_节点:
        fputc('\'', 输出文件);
        文件_写入utf8字符(输出文件, unicode转utf8(((基本表达式节点*)节点指针)->值.字符));
        fputc('\'', 输出文件);
        break;
    case 字符串字面量_节点:
        fputc('"', 输出文件);
        unicode切片_文件打印(((基本表达式节点*)节点指针)->值.字符串, 输出文件); 
        fputc('"', 输出文件);
        break;
    default:
        fprintf(stderr, "不明类型节点\n"); 
        break;
    }
}

//gcc -g -Wall parser.c lexer.c ../散列表_unicode切片_编码/散列表_unicode切片_编码.c ../unicode切片/unicode切片.c ../utf8_unicode/utf8_unicode.c && ./a.out
// int main() {
//     解析器调试输出文件 = stdout;
//     输入文件_语法分析 = fopen("parser_test.go", "r");
//     三元节点 * 节点;
//     // 部分测试
//     // 读入下一单词();
//     节点 = 文件_解析();
//     // 查看
//     解析器_声明前缀打印(解析器调试输出文件, 节点);
//     // 
//     fputc('\n', 解析器调试输出文件);
// }
